summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/child/ext-webRequest.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--toolkit/components/extensions/child/ext-webRequest.js119
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 };
+ }
+};