Bug 1442427 - Log rejected promises from webextension listeners
MozReview-Commit-ID: 5kzv5yM6ZJW
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -223,17 +223,20 @@ this.browserAction = class extends Exten
Cu.reportError(e);
event.preventDefault();
}
} else {
TelemetryStopwatch.cancel(POPUP_OPEN_MS_HISTOGRAM, this);
// This isn't not a hack, but it seems to provide the correct behavior
// with the fewest complications.
event.preventDefault();
- this.emit("click", tabbrowser.selectedBrowser);
+ this.emit("click", tabbrowser.selectedBrowser).catch(error => {
+ Cu.reportError(Object.assign(new Error(""), error));
+ throw error;
+ });
// Ensure we close any popups this node was in:
CustomizableUI.hidePanelForNode(event.target);
}
},
});
this.tabContext.on("tab-select", // eslint-disable-line mozilla/balanced-listeners
(evt, tab) => { this.updateWindow(tab.ownerGlobal); });
@@ -586,20 +589,22 @@ this.browserAction = class extends Exten
return tabTracker.getTab(tabId);
}
return null;
}
return {
browserAction: {
onClicked: new InputEventManager(context, "browserAction.onClicked", fire => {
- let listener = (event, browser) => {
+ let listener = (event, browser) =>
context.withPendingBrowser(browser, () =>
- fire.sync(tabManager.convert(tabTracker.activeTab)));
- };
+ fire.sync(tabManager.convert(tabTracker.activeTab))).catch(error => {
+ Cu.reportError(Object.assign(new Error(""), error));
+ throw error;
+ });
browserAction.on("click", listener);
return () => {
browserAction.off("click", listener);
};
}).api(),
enable: function(tabId) {
let tab = getTab(tabId);
--- a/toolkit/components/extensions/ExtensionChild.jsm
+++ b/toolkit/components/extensions/ExtensionChild.jsm
@@ -871,28 +871,32 @@ class ChildAPIManager {
return Promise.resolve(
data.handlingUserInput ? withHandlingUserInput(this.context.contentWindow, fire)
: fire())
.then(result => {
if (result !== undefined) {
return new StructuredCloneHolder(result, this.context.cloneScope);
}
return result;
+ }, error => {
+ Cu.reportError(error);
+ throw error;
});
}
if (!map.removedIds.has(data.listenerId)) {
Services.console.logStringMessage(
`Unknown listener at childId=${data.childId} path=${data.path} listenerId=${data.listenerId}\n`);
}
break;
case "API:CallResult":
let deferred = this.callPromises.get(data.callId);
if ("error" in data) {
deferred.reject(data.error);
+ Cu.reportError(data.error);
} else {
let result = data.result.deserialize(this.context.cloneScope);
deferred.resolve(new NoCloneSpreadArgs(result));
}
this.callPromises.delete(data.callId);
break;
}
--- a/toolkit/components/extensions/ExtensionCommon.jsm
+++ b/toolkit/components/extensions/ExtensionCommon.jsm
@@ -357,17 +357,20 @@ class BaseContext {
*/
sendMessage(target, messageName, data, options = {}) {
options.recipient = Object.assign({extensionId: this.extension.id}, options.recipient);
options.sender = options.sender || {};
options.sender.extensionId = this.extension.id;
options.sender.contextId = this.contextId;
- return MessageChannel.sendMessage(target, messageName, data, options);
+ return MessageChannel.sendMessage(target, messageName, data, options).catch(error => {
+ Cu.reportError(Object.assign(new Error(""), error));
+ throw error;
+ });
}
get lastError() {
this.checkedLastError = true;
return this._lastError;
}
set lastError(val) {
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -421,29 +421,35 @@ class ProxyContextParent extends BaseCon
}
async withPendingBrowser(browser, callable) {
let savedBrowser = this.pendingEventBrowser;
this.pendingEventBrowser = browser;
try {
let result = await callable();
return result;
+ } catch (error) {
+ Cu.reportError(Object.assign(new Error(""), error));
+ throw error;
} finally {
this.pendingEventBrowser = savedBrowser;
}
}
get cloneScope() {
return this.sandbox;
}
applySafe(callback, args) {
// There's no need to clone when calling listeners for a proxied
// context.
- return this.applySafeWithoutClone(callback, args);
+ return this.applySafeWithoutClone(callback, args).catch(error => {
+ Cu.reportError(Object.assign(new Error(""), error));
+ throw error;
+ });
}
get xulBrowser() {
return this.messageManagerProxy.eventTarget;
}
get parentMessageManager() {
return this.messageManagerProxy.messageManager;
@@ -810,16 +816,19 @@ ParentAPIManager = {
},
},
{
lowPriority,
recipient: {childId},
})
.then(result => {
return result && result.deserialize(global);
+ }, error => {
+ Cu.reportError(Object.assign(new Error(""), error));
+ throw error;
});
}
context.listenerProxies.set(data.listenerId, listener);
let args = data.args;
let promise = context.apiCan.asyncFindAPIPath(data.path);
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -238,17 +238,20 @@ class EventEmitter {
promises.push(result);
}
} catch (e) {
Cu.reportError(e);
}
}
if (promises.length) {
- return Promise.all(promises);
+ return Promise.all(promises).catch(error => {
+ Cu.reportError(Object.assign(new Error(""), error));
+ throw error;
+ });
}
}
}
}
/**
* A set with a limited number of slots, which flushes older entries as
* newer ones are added.