Bug 1403369 - Correctly handle content-side errors in tabs.executeScript(). r=zombie, a=ritu
authorKris Maglione <maglione.k@gmail.com>
Tue, 26 Sep 2017 15:33:11 -0700
changeset 432368 3ff5988c85fb0e30a73e2a2dcbfd8c57fad9b4ce
parent 432367 76ace2631acc7cb8e12a449089235be1c10f0831
child 432369 5a16f28245b01b4483311578572adfc8eca9efe2
push id7946
push userryanvm@gmail.com
push dateWed, 11 Oct 2017 17:47:53 +0000
treeherdermozilla-beta@465b880a2af9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerszombie, ritu
bugs1403369
milestone57.0
Bug 1403369 - Correctly handle content-side errors in tabs.executeScript(). r=zombie, a=ritu MozReview-Commit-ID: CPRV9PvWe9e
toolkit/components/extensions/ExtensionContent.jsm
--- 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.
+      }
     }
   },
 };