forked from mirrors/gecko-dev
This patch updates every use of EventManager in child/ext-*.js files that can referenced from extension contexts of envType "addon_child". Pre patch, these could trigger "background-script-reset-idle" and result in triggering "background-script-reset-idle" in the parent despite the background being stopped, and consequently trigger the reported bug. The previous patch fixes the negative consequence of this unexpected event, this patch fixes an underlying cause by removing the triggers. Forcing resetIdleOnEvent to false does not have any negative impact on these modules, because all of these events are dependencies of an EventManager in the parent, which already activates the functionality associated with resetIdleOnEvent=true. To minimize the likelihood of affecting unit tests, this patch keeps the EventManager of test.onMessage at resetIdleOnEvent=true as before, and defers to bug 1901294 for changing it to false. Original Revision: https://phabricator.services.mozilla.com/D215298 Differential Revision: https://phabricator.services.mozilla.com/D216987
157 lines
4.7 KiB
JavaScript
157 lines
4.7 KiB
JavaScript
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* vim: set sts=2 sw=2 et tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
var { ExtensionError } = ExtensionUtils;
|
|
|
|
this.webRequest = class extends ExtensionAPI {
|
|
STREAM_FILTER_INACTIVE_STATUSES = ["closed", "disconnected", "failed"];
|
|
|
|
hasActiveStreamFilter(filtersWeakSet) {
|
|
const iter = ChromeUtils.nondeterministicGetWeakSetKeys(filtersWeakSet);
|
|
for (let filter of iter) {
|
|
if (!this.STREAM_FILTER_INACTIVE_STATUSES.includes(filter.status)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
watchStreamFilterSuspendCancel({
|
|
context,
|
|
filters,
|
|
onSuspend,
|
|
onSuspendCanceled,
|
|
}) {
|
|
if (
|
|
!context.isBackgroundContext ||
|
|
context.extension.persistentBackground !== false
|
|
) {
|
|
return;
|
|
}
|
|
|
|
const { extension } = context;
|
|
const cancelSuspendOnActiveStreamFilter = () =>
|
|
this.hasActiveStreamFilter(filters);
|
|
context.callOnClose({
|
|
close() {
|
|
extension.off(
|
|
"internal:stream-filter-suspend-cancel",
|
|
cancelSuspendOnActiveStreamFilter
|
|
);
|
|
extension.off("background-script-suspend", onSuspend);
|
|
extension.off("background-script-suspend-canceled", onSuspend);
|
|
},
|
|
});
|
|
extension.on(
|
|
"internal:stream-filter-suspend-cancel",
|
|
cancelSuspendOnActiveStreamFilter
|
|
);
|
|
extension.on("background-script-suspend", onSuspend);
|
|
extension.on("background-script-suspend-canceled", onSuspendCanceled);
|
|
}
|
|
|
|
getAPI(context) {
|
|
let filters = new WeakSet();
|
|
|
|
context.callOnClose({
|
|
close() {
|
|
for (let filter of ChromeUtils.nondeterministicGetWeakSetKeys(
|
|
filters
|
|
)) {
|
|
try {
|
|
filter.disconnect();
|
|
} catch (e) {
|
|
// Ignore.
|
|
}
|
|
}
|
|
},
|
|
});
|
|
|
|
let isSuspending = false;
|
|
this.watchStreamFilterSuspendCancel({
|
|
context,
|
|
filters,
|
|
onSuspend: () => (isSuspending = true),
|
|
onSuspendCanceled: () => (isSuspending = false),
|
|
});
|
|
|
|
function filterResponseData(requestId) {
|
|
if (isSuspending) {
|
|
throw new ExtensionError(
|
|
"filterResponseData method calls forbidden while background extension global is suspending"
|
|
);
|
|
}
|
|
requestId = parseInt(requestId, 10);
|
|
|
|
let streamFilter = context.cloneScope.StreamFilter.create(
|
|
requestId,
|
|
context.extension.id
|
|
);
|
|
|
|
filters.add(streamFilter);
|
|
return streamFilter;
|
|
}
|
|
|
|
const webRequest = {
|
|
onAuthRequired: new EventManager({
|
|
context,
|
|
name: "webRequest.onAuthRequired",
|
|
// Parent event already resets idle if needed, no need to do it here.
|
|
resetIdleOnEvent: false,
|
|
register: (fire, filter, extra) => {
|
|
const listener = details => {
|
|
// NOTE: asyncBlocking and blocking are mutually exclusive
|
|
// (and an error raised synchronously from schema based
|
|
// validation).
|
|
if (!extra.includes("asyncBlocking")) {
|
|
// NOTE: may return the result or a Promise.
|
|
return fire.raw(details);
|
|
}
|
|
|
|
// Wrap the call into a promise resolved with what the extension
|
|
// passed to the additional asyncCallback parameter.
|
|
let asyncCallback;
|
|
const promise = new Promise(resolve => {
|
|
asyncCallback = Cu.exportFunction(value => {
|
|
resolve(value);
|
|
}, context.cloneScope);
|
|
});
|
|
// Return value is ignored on asyncBlocking listeners
|
|
// (chrome compatible behavior).
|
|
fire.raw(details, asyncCallback);
|
|
return promise;
|
|
};
|
|
const parentEvent = context.childManager.getParentEvent(
|
|
"webRequest.onAuthRequired"
|
|
);
|
|
parentEvent.addListener(listener, filter, extra);
|
|
return () => {
|
|
parentEvent.removeListener(listener);
|
|
};
|
|
},
|
|
}).api(),
|
|
};
|
|
|
|
// For extensions with manifest_version >= 3, an additional webRequestFilterResponse permission
|
|
// is required to get access to the webRequest.filterResponseData API method.
|
|
if (
|
|
context.extension.manifestVersion < 3 ||
|
|
context.extension.hasPermission("webRequestFilterResponse")
|
|
) {
|
|
webRequest.filterResponseData = filterResponseData;
|
|
} else {
|
|
webRequest.filterResponseData = () => {
|
|
throw new ExtensionError(
|
|
'Missing required "webRequestFilterResponse" permission'
|
|
);
|
|
};
|
|
}
|
|
|
|
return { webRequest };
|
|
}
|
|
};
|