diff options
Diffstat (limited to 'toolkit/components/extensions/child/ext-webRequest.js')
-rw-r--r-- | toolkit/components/extensions/child/ext-webRequest.js | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/toolkit/components/extensions/child/ext-webRequest.js b/toolkit/components/extensions/child/ext-webRequest.js new file mode 100644 index 0000000000..49bdd3f232 --- /dev/null +++ b/toolkit/components/extensions/child/ext-webRequest.js @@ -0,0 +1,119 @@ +/* -*- 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 = {}; + + // 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 }; + } +}; |