зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 27 changesets (bug 1688040) for causing multiple failures. CLOSED TREE
Backed out changeset 85ba163b6423 (bug 1688040) Backed out changeset 36cdc1600e66 (bug 1688040) Backed out changeset 88395ab5a5b5 (bug 1688040) Backed out changeset 8d33bdd8d0b8 (bug 1688040) Backed out changeset fdbced7a94f3 (bug 1688040) Backed out changeset 922ca2f20fa1 (bug 1688040) Backed out changeset 7fc233bf144c (bug 1688040) Backed out changeset 64221db54d98 (bug 1688040) Backed out changeset 4d9b2a9dd247 (bug 1688040) Backed out changeset c8d890f1a8e2 (bug 1688040) Backed out changeset 81e957717eb1 (bug 1688040) Backed out changeset b7dcade29dab (bug 1688040) Backed out changeset 20e38838aa89 (bug 1688040) Backed out changeset 08737e7ea047 (bug 1688040) Backed out changeset b82645d5b7c7 (bug 1688040) Backed out changeset db374d34839a (bug 1688040) Backed out changeset 6a2ebb56325d (bug 1688040) Backed out changeset 7d0ce555263f (bug 1688040) Backed out changeset 15e0689a57f0 (bug 1688040) Backed out changeset d7d6b1bec92a (bug 1688040) Backed out changeset 615b683acb00 (bug 1688040) Backed out changeset 49d3e1baf577 (bug 1688040) Backed out changeset 30cc613912ce (bug 1688040) Backed out changeset d413ec19bded (bug 1688040) Backed out changeset cfdf6e87d820 (bug 1688040) Backed out changeset f719b9d0bc25 (bug 1688040) Backed out changeset 925f23a58da6 (bug 1688040)
This commit is contained in:
Родитель
56f2e3276e
Коммит
925895e1ed
|
@ -1612,21 +1612,6 @@ DOMInterfaces = {
|
|||
'nativeType': 'mozilla::extensions::ExtensionPort',
|
||||
},
|
||||
|
||||
'ExtensionRuntime': {
|
||||
'headerFile': 'mozilla/extensions/ExtensionRuntime.h',
|
||||
'nativeType': 'mozilla::extensions::ExtensionRuntime',
|
||||
},
|
||||
|
||||
'ExtensionTest': {
|
||||
'headerFile': 'mozilla/extensions/ExtensionTest.h',
|
||||
'nativeType': 'mozilla::extensions::ExtensionTest',
|
||||
},
|
||||
|
||||
'ExtensionAlarms': {
|
||||
'headerFile': 'mozilla/extensions/ExtensionAlarms.h',
|
||||
'nativeType': 'mozilla::extensions::ExtensionAlarms',
|
||||
},
|
||||
|
||||
####################################
|
||||
# Test Interfaces of various sorts #
|
||||
####################################
|
||||
|
|
|
@ -421,6 +421,3 @@ ElementSetCaptureWarning=Element.setCapture() is deprecated. Use Element.setPoin
|
|||
ElementReleaseCaptureWarning=Element.releaseCapture() is deprecated. Use Element.releasePointerCapture() instead. For more help https://developer.mozilla.org/docs/Web/API/Element/releasePointerCapture
|
||||
# LOCALIZATION NOTE: Do not translate "Document.releaseCapture()" and "Element.releasePointerCapture()".
|
||||
DocumentReleaseCaptureWarning=Document.releaseCapture() is deprecated. Use Element.releasePointerCapture() instead. For more help https://developer.mozilla.org/docs/Web/API/Element/releasePointerCapture
|
||||
|
||||
# LOCALIZATION NOTE: Don't translate browser.runtime.lastError, %S is the error message from the unchecked value set on browser.runtime.lastError.
|
||||
WebExtensionUncheckedLastError=browser.runtime.lastError value was not checked: %S
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT
|
||||
*
|
||||
* The content of this file has been generated based on the WebExtensions API
|
||||
* JSONSchema using the following command:
|
||||
*
|
||||
* export SCRIPT_DIR="toolkit/components/extensions/webidl-api"
|
||||
* mach python $SCRIPT_DIR/GenerateWebIDLBindings.py -- alarms
|
||||
*
|
||||
* More info about generating webidl API bindings for WebExtensions API at:
|
||||
*
|
||||
* https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/webidl_bindings.html
|
||||
*/
|
||||
|
||||
/* 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/.
|
||||
*
|
||||
* You are granted a license to use, reproduce and create derivative works of
|
||||
* this document.
|
||||
*/
|
||||
|
||||
// WebIDL definition for the "alarms" WebExtensions API
|
||||
[Exposed=(ServiceWorker), LegacyNoInterfaceObject]
|
||||
interface ExtensionAlarms {
|
||||
// API methods.
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void create(optional DOMString name, any alarmInfo);
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any get(optional DOMString name, optional Function callback);
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any getAll(optional Function callback);
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any clear(optional DOMString name, optional Function callback);
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any clearAll(optional Function callback);
|
||||
|
||||
// API events.
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onAlarm;
|
||||
};
|
|
@ -16,7 +16,7 @@
|
|||
[Exposed=(ServiceWorker)]
|
||||
interface mixin ExtensionGlobalsMixin {
|
||||
[Replaceable, SameObject, BinaryName="AcquireExtensionBrowser",
|
||||
BindingAlias="chrome", Func="extensions::ExtensionAPIAllowed"]
|
||||
Func="extensions::ExtensionAPIAllowed"]
|
||||
readonly attribute ExtensionBrowser browser;
|
||||
};
|
||||
|
||||
|
@ -29,19 +29,4 @@ interface ExtensionBrowser {
|
|||
Func="mozilla::extensions::ExtensionMockAPI::IsAllowed",
|
||||
Pref="extensions.webidl-api.expose_mock_interface"]
|
||||
readonly attribute ExtensionMockAPI mockExtensionAPI;
|
||||
|
||||
// `browser.alarms` API namespace
|
||||
[Replaceable, SameObject, BinaryName="GetExtensionAlarms",
|
||||
Func="mozilla::extensions::ExtensionAlarms::IsAllowed"]
|
||||
readonly attribute ExtensionAlarms alarms;
|
||||
|
||||
// `browser.runtime` API namespace
|
||||
[Replaceable, SameObject, BinaryName="GetExtensionRuntime",
|
||||
Func="mozilla::extensions::ExtensionRuntime::IsAllowed"]
|
||||
readonly attribute ExtensionRuntime runtime;
|
||||
|
||||
// `browser.test` API namespace, available in tests.
|
||||
[Replaceable, SameObject, BinaryName="GetExtensionTest",
|
||||
Func="mozilla::extensions::ExtensionTest::IsAllowed"]
|
||||
readonly attribute ExtensionTest test;
|
||||
};
|
||||
|
|
|
@ -14,9 +14,9 @@ interface ExtensionPort {
|
|||
[Replaceable]
|
||||
readonly attribute DOMString name;
|
||||
[Replaceable]
|
||||
readonly attribute any sender;
|
||||
readonly attribute object sender;
|
||||
[Replaceable]
|
||||
readonly attribute any error;
|
||||
readonly attribute object? error;
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void disconnect();
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT
|
||||
*
|
||||
* The content of this file has been generated based on the WebExtensions API
|
||||
* JSONSchema using the following command:
|
||||
*
|
||||
* export SCRIPT_DIR="toolkit/components/extensions/webidl-api"
|
||||
* mach python $SCRIPT_DIR/GenerateWebIDLBindings.py -- runtime
|
||||
*
|
||||
* More info about generating webidl API bindings for WebExtensions API at:
|
||||
*
|
||||
* https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/webidl_bindings.html
|
||||
*/
|
||||
|
||||
/* 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/.
|
||||
*
|
||||
* You are granted a license to use, reproduce and create derivative works of
|
||||
* this document.
|
||||
*/
|
||||
|
||||
// WebIDL definition for the "runtime" WebExtensions API
|
||||
[Exposed=(ServiceWorker), LegacyNoInterfaceObject]
|
||||
interface ExtensionRuntime {
|
||||
// API methods.
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any openOptionsPage(optional Function callback);
|
||||
|
||||
[Throws, WebExtensionStub]
|
||||
any getManifest();
|
||||
|
||||
[Throws, WebExtensionStub="ReturnsString"]
|
||||
DOMString getURL(DOMString path);
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any setUninstallURL(optional DOMString url, optional Function callback);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void reload();
|
||||
|
||||
[Throws, WebExtensionStub="ReturnsPort"]
|
||||
ExtensionPort connect(optional DOMString extensionId, optional any connectInfo);
|
||||
|
||||
[Throws, WebExtensionStub="ReturnsPort"]
|
||||
ExtensionPort connectNative(DOMString application);
|
||||
|
||||
[Throws, WebExtensionStub="AsyncAmbiguous"]
|
||||
any sendMessage(any... args);
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any sendNativeMessage(DOMString application, any message, optional Function responseCallback);
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any getBrowserInfo(optional Function callback);
|
||||
|
||||
[Throws, WebExtensionStub="Async"]
|
||||
any getPlatformInfo(optional Function callback);
|
||||
|
||||
// API events.
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onStartup;
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onInstalled;
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onUpdateAvailable;
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onConnect;
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onConnectExternal;
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onMessage;
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onMessageExternal;
|
||||
|
||||
// API properties.
|
||||
|
||||
[Replaceable]
|
||||
readonly attribute any lastError;
|
||||
|
||||
[Replaceable]
|
||||
readonly attribute DOMString id;
|
||||
};
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT
|
||||
*
|
||||
* The content of this file has been generated based on the WebExtensions API
|
||||
* JSONSchema using the following command:
|
||||
*
|
||||
* export SCRIPT_DIR="toolkit/components/extensions/webidl-api"
|
||||
* mach python $SCRIPT_DIR/GenerateWebIDLBindings.py -- test
|
||||
*
|
||||
* More info about generating webidl API bindings for WebExtensions API at:
|
||||
*
|
||||
* https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/webidl_bindings.html
|
||||
*/
|
||||
|
||||
/* 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/.
|
||||
*
|
||||
* You are granted a license to use, reproduce and create derivative works of
|
||||
* this document.
|
||||
*/
|
||||
|
||||
// WebIDL definition for the "test" WebExtensions API
|
||||
[Exposed=(ServiceWorker), LegacyNoInterfaceObject]
|
||||
interface ExtensionTest {
|
||||
// API methods.
|
||||
|
||||
[Throws, WebExtensionStub="NotImplementedNoReturn"]
|
||||
void withHandlingUserInput(Function callback);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void notifyFail(DOMString message);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void notifyPass(optional DOMString message);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void log(DOMString message);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void sendMessage(any... args);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void fail(optional any message);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void succeed(optional any message);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void assertTrue(any... args);
|
||||
|
||||
[Throws, WebExtensionStub="NoReturn"]
|
||||
void assertFalse(any... args);
|
||||
|
||||
[Throws, WebExtensionStub="NotImplementedNoReturn"]
|
||||
void assertEq(any... args);
|
||||
|
||||
[Throws, WebExtensionStub="NotImplementedAsync"]
|
||||
any assertRejects(Promise<any> promise, any expectedError, optional DOMString message, optional Function callback);
|
||||
|
||||
[Throws, WebExtensionStub="NotImplementedNoReturn"]
|
||||
void assertThrows(Function func, any expectedError, optional DOMString message);
|
||||
|
||||
// API events.
|
||||
|
||||
[Replaceable, SameObject]
|
||||
readonly attribute ExtensionEventManager onMessage;
|
||||
};
|
|
@ -1058,14 +1058,11 @@ WEBIDL_FILES += [
|
|||
|
||||
# WebExtensions API.
|
||||
WEBIDL_FILES += [
|
||||
"ExtensionAlarms.webidl",
|
||||
"ExtensionBrowser.webidl",
|
||||
"ExtensionEventManager.webidl",
|
||||
# ExtensionMockAPI is not a real WebExtensions API, and it is only enabled in tests.
|
||||
"ExtensionMockAPI.webidl",
|
||||
"ExtensionPort.webidl",
|
||||
"ExtensionRuntime.webidl",
|
||||
"ExtensionTest.webidl",
|
||||
]
|
||||
|
||||
# We only expose our prefable test interfaces in debug builds, just to be on
|
||||
|
|
|
@ -15,11 +15,7 @@
|
|||
* @prop {object} arg
|
||||
*/
|
||||
|
||||
const EXPORTED_SYMBOLS = [
|
||||
"BaseConduit",
|
||||
"ConduitsChild",
|
||||
"ProcessConduitsChild",
|
||||
];
|
||||
const EXPORTED_SYMBOLS = ["BaseConduit", "ConduitsChild"];
|
||||
|
||||
/**
|
||||
* Base class for both child (Point) and parent (Broadcast) side of conduits,
|
||||
|
@ -198,18 +194,3 @@ class ConduitsChild extends JSWindowActorChild {
|
|||
this.conduits.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Child side of the Conduits process actor. Same code as JSWindowActor.
|
||||
*/
|
||||
class ProcessConduitsChild extends JSProcessActorChild {
|
||||
constructor() {
|
||||
super();
|
||||
this.conduits = new Map();
|
||||
}
|
||||
|
||||
openConduit = ConduitsChild.prototype.openConduit;
|
||||
receiveMessage = ConduitsChild.prototype.receiveMessage;
|
||||
willDestroy = ConduitsChild.prototype.willDestroy;
|
||||
didDestroy = ConduitsChild.prototype.didDestroy;
|
||||
}
|
||||
|
|
|
@ -3,11 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const EXPORTED_SYMBOLS = [
|
||||
"BroadcastConduit",
|
||||
"ConduitsParent",
|
||||
"ProcessConduitsParent",
|
||||
];
|
||||
const EXPORTED_SYMBOLS = ["BroadcastConduit", "ConduitsParent"];
|
||||
|
||||
/**
|
||||
* This @file implements the parent side of Conduits, an abstraction over
|
||||
|
@ -113,47 +109,15 @@ const Hub = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Confirm that a remote conduit comes from an extension background
|
||||
* service worker.
|
||||
* Confirm that a remote conduit comes from an extension page.
|
||||
* @see ExtensionPolicyService::CheckParentFrames
|
||||
* @param {ConduitAddress} remote
|
||||
* @returns {boolean}
|
||||
*/
|
||||
verifyWorkerEnv({ actor, extensionId, workerScriptURL }) {
|
||||
const addonPolicy = WebExtensionPolicy.getByID(extensionId);
|
||||
if (!addonPolicy) {
|
||||
throw new Error(`No WebExtensionPolicy found for ${extensionId}`);
|
||||
}
|
||||
if (actor.manager.remoteType !== addonPolicy.extension.remoteType) {
|
||||
throw new Error(
|
||||
`Bad ${extensionId} process: ${actor.manager.remoteType}`
|
||||
);
|
||||
}
|
||||
if (!addonPolicy.isManifestBackgroundWorker(workerScriptURL)) {
|
||||
throw new Error(
|
||||
`Bad ${extensionId} background service worker script url: ${workerScriptURL}`
|
||||
);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Confirm that a remote conduit comes from an extension page or
|
||||
* an extension background service worker.
|
||||
* @see ExtensionPolicyService::CheckParentFrames
|
||||
* @param {ConduitAddress} remote
|
||||
* @returns {boolean}
|
||||
*/
|
||||
verifyEnv({ actor, envType, extensionId, ...rest }) {
|
||||
verifyEnv({ actor, envType, extensionId }) {
|
||||
if (!extensionId || !ADDON_ENV.has(envType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ProcessConduit related to a background service worker context.
|
||||
if (actor.manager && actor.manager instanceof Ci.nsIDOMProcessParent) {
|
||||
return this.verifyWorkerEnv({ actor, envType, extensionId, ...rest });
|
||||
}
|
||||
|
||||
let windowGlobal = actor.manager;
|
||||
|
||||
while (windowGlobal) {
|
||||
|
@ -182,19 +146,8 @@ const Hub = {
|
|||
fillInAddress(address, actor) {
|
||||
address.actor = actor;
|
||||
address.verified = this.verifyEnv(address);
|
||||
if (actor instanceof JSWindowActorParent) {
|
||||
address.frameId = WebNavigationFrames.getFrameId(actor.browsingContext);
|
||||
address.url = actor.browsingContext.currentURI.spec;
|
||||
} else {
|
||||
// Background service worker contexts do not have an associated frame
|
||||
// and there is no browsingContext to retrieve the expected url from.
|
||||
//
|
||||
// WorkerContextChild sent in the address part of the ConduitOpened request
|
||||
// the worker script URL as address.workerScriptURL, and so we can use that
|
||||
// as the address.url too.
|
||||
address.frameId = -1;
|
||||
address.url = address.workerScriptURL;
|
||||
}
|
||||
address.frameId = WebNavigationFrames.getFrameId(actor.browsingContext);
|
||||
address.url = actor.browsingContext.currentURI.spec;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -317,12 +270,9 @@ class BroadcastConduit extends BaseConduit {
|
|||
// Target Messengers by extensionId, tabId (topBC) and frameId.
|
||||
tab: remote =>
|
||||
remote.extensionId === arg.extensionId &&
|
||||
remote.actor.manager.browsingContext?.top.id === arg.topBC &&
|
||||
remote.actor.manager.browsingContext.top.id === arg.topBC &&
|
||||
(arg.frameId == null || remote.frameId === arg.frameId) &&
|
||||
remote.recv.includes(method),
|
||||
|
||||
// Target Messengers by extensionId.
|
||||
extension: remote => remote.instanceId === arg.instanceId,
|
||||
};
|
||||
|
||||
let targets = Array.from(Hub.remotes.values()).filter(filters[kind]);
|
||||
|
@ -457,12 +407,3 @@ class ConduitsParent extends JSWindowActorParent {
|
|||
Hub.actorClosed(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parent side of the Conduits process actor. Same code as JSWindowActor.
|
||||
*/
|
||||
class ProcessConduitsParent extends JSProcessActorParent {
|
||||
receiveMessage = ConduitsParent.prototype.receiveMessage;
|
||||
willDestroy = ConduitsParent.prototype.willDestroy;
|
||||
didDestroy = ConduitsParent.prototype.didDestroy;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,6 @@ const { ExtensionUtils } = ChromeUtils.import(
|
|||
const { DefaultMap, ExtensionError, LimitedSet, getUniqueId } = ExtensionUtils;
|
||||
|
||||
const {
|
||||
defineLazyGetter,
|
||||
EventEmitter,
|
||||
EventManager,
|
||||
LocalAPIImplementation,
|
||||
|
@ -251,9 +250,8 @@ class Port {
|
|||
*/
|
||||
constructor(context, portId, name, native, sender) {
|
||||
this.context = context;
|
||||
this.name = name;
|
||||
this.sender = sender;
|
||||
this.holdMessage = native ? data => holdMessage(data, this) : holdMessage;
|
||||
|
||||
this.conduit = context.openConduit(this, {
|
||||
portId,
|
||||
native,
|
||||
|
@ -261,26 +259,21 @@ class Port {
|
|||
recv: ["PortMessage", "PortDisconnect"],
|
||||
send: ["PortMessage"],
|
||||
});
|
||||
this.initEventManagers();
|
||||
}
|
||||
|
||||
initEventManagers() {
|
||||
const { context } = this;
|
||||
this.onMessage = new SimpleEventAPI(context, "Port.onMessage");
|
||||
this.onDisconnect = new SimpleEventAPI(context, "Port.onDisconnect");
|
||||
}
|
||||
|
||||
getAPI() {
|
||||
// Public Port object handed to extensions from `connect()` and `onConnect`.
|
||||
return {
|
||||
name: this.name,
|
||||
sender: this.sender,
|
||||
let api = {
|
||||
name,
|
||||
sender,
|
||||
error: null,
|
||||
onMessage: this.onMessage.api(),
|
||||
onDisconnect: this.onDisconnect.api(),
|
||||
postMessage: this.sendPortMessage.bind(this),
|
||||
disconnect: () => this.conduit.close(),
|
||||
};
|
||||
this.api = Cu.cloneInto(api, context.cloneScope, { cloneFunctions: true });
|
||||
}
|
||||
|
||||
recvPortMessage({ holder }) {
|
||||
|
@ -303,11 +296,6 @@ class Port {
|
|||
}
|
||||
}
|
||||
|
||||
defineLazyGetter(Port.prototype, "api", function() {
|
||||
let api = this.getAPI();
|
||||
return Cu.cloneInto(api, this.context.cloneScope, { cloneFunctions: true });
|
||||
});
|
||||
|
||||
/**
|
||||
* Each extension context gets its own Messenger object. It handles the
|
||||
* basics of sendMessage, onMessage, connect and onConnect.
|
||||
|
@ -320,11 +308,7 @@ class Messenger {
|
|||
query: ["NativeMessage", "RuntimeMessage", "PortConnect"],
|
||||
recv: ["RuntimeMessage", "PortConnect"],
|
||||
});
|
||||
this.initEventManagers();
|
||||
}
|
||||
|
||||
initEventManagers() {
|
||||
const { context } = this;
|
||||
this.onConnect = new SimpleEventAPI(context, "runtime.onConnect");
|
||||
this.onConnectEx = new SimpleEventAPI(context, "runtime.onConnectExternal");
|
||||
this.onMessage = new MessageEvent(context, "runtime.onMessage");
|
||||
|
@ -736,10 +720,9 @@ class ChildLocalAPIImplementation extends LocalAPIImplementation {
|
|||
}
|
||||
|
||||
// We create one instance of this class for every extension context that
|
||||
// needs to use remote APIs. It uses the the JSWindowActor and
|
||||
// JSProcessActor Conduits actors (see ConduitsChild.jsm) to communicate
|
||||
// with the ParentAPIManager singleton in ExtensionParent.jsm.
|
||||
// It handles asynchronous function calls as well as event listeners.
|
||||
// needs to use remote APIs. It uses the message manager to communicate
|
||||
// with the ParentAPIManager singleton in ExtensionParent.jsm. It
|
||||
// handles asynchronous function calls as well as event listeners.
|
||||
class ChildAPIManager {
|
||||
constructor(context, messageManager, localAPICan, contextData) {
|
||||
this.context = context;
|
||||
|
@ -988,536 +971,8 @@ class ChildAPIManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SimpleEventAPI subclass specialized for the worker port events
|
||||
* used by WorkerMessenger.
|
||||
*/
|
||||
class WorkerRuntimePortEvent extends SimpleEventAPI {
|
||||
api() {
|
||||
return {
|
||||
...super.api(),
|
||||
createListenerForAPIRequest: (...args) =>
|
||||
this.createListenerForAPIRequest(...args),
|
||||
};
|
||||
}
|
||||
|
||||
createListenerForAPIRequest(request) {
|
||||
const { eventListener } = request;
|
||||
return function(port, ...args) {
|
||||
return eventListener.callListener(args, {
|
||||
apiObjectType: Ci.mozIExtensionListenerCallOptions.RUNTIME_PORT,
|
||||
apiObjectDescriptor: { portId: port.portId, name: port.name },
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SimpleEventAPI subclass specialized for the worker runtime messaging events
|
||||
* used by WorkerMessenger.
|
||||
*/
|
||||
class WorkerMessageEvent extends MessageEvent {
|
||||
api() {
|
||||
return {
|
||||
...super.api(),
|
||||
createListenerForAPIRequest: (...args) =>
|
||||
this.createListenerForAPIRequest(...args),
|
||||
};
|
||||
}
|
||||
|
||||
createListenerForAPIRequest(request) {
|
||||
const { eventListener } = request;
|
||||
return function(message, sender) {
|
||||
return eventListener.callListener([message, sender], {
|
||||
eventListenerType:
|
||||
Ci.mozIExtensionListenerCallOptions.CALLBACK_SEND_RESPONSE,
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MessageEvent subclass specialized for the worker's port API events
|
||||
* used by WorkerPort.
|
||||
*/
|
||||
class WorkerPortEvent extends SimpleEventAPI {
|
||||
api() {
|
||||
return {
|
||||
...super.api(),
|
||||
createListenerForAPIRequest: (...args) =>
|
||||
this.createListenerForAPIRequest(...args),
|
||||
};
|
||||
}
|
||||
|
||||
createListenerForAPIRequest(request) {
|
||||
const { eventListener } = request;
|
||||
switch (this.name) {
|
||||
case "Port.onDisconnect":
|
||||
return function(port) {
|
||||
eventListener.callListener([], {
|
||||
apiObjectType: Ci.mozIExtensionListenerCallOptions.RUNTIME_PORT,
|
||||
apiObjectDescriptor: {
|
||||
portId: port.portId,
|
||||
name: port.name,
|
||||
},
|
||||
});
|
||||
};
|
||||
case "Port.onMessage":
|
||||
return function(message, port) {
|
||||
eventListener.callListener([message], {
|
||||
apiObjectType: Ci.mozIExtensionListenerCallOptions.RUNTIME_PORT,
|
||||
apiObjectDescriptor: {
|
||||
portId: port.portId,
|
||||
name: port.name,
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Port subclass specialized for the workers and used by WorkerMessager.
|
||||
*/
|
||||
class WorkerPort extends Port {
|
||||
constructor(context, portId, name, native, sender) {
|
||||
const { viewType, contextId } = context;
|
||||
if (viewType !== "background_worker") {
|
||||
throw new Error(
|
||||
`Unexpected viewType "${viewType}" on context ${contextId}`
|
||||
);
|
||||
}
|
||||
|
||||
super(context, portId, name, native, sender);
|
||||
this.portId = portId;
|
||||
}
|
||||
|
||||
initEventManagers() {
|
||||
const { context } = this;
|
||||
this.onMessage = new WorkerPortEvent(context, "Port.onMessage");
|
||||
this.onDisconnect = new WorkerPortEvent(context, "Port.onDisconnect");
|
||||
}
|
||||
|
||||
getAPI() {
|
||||
const api = super.getAPI();
|
||||
// Add the portId to the API object, needed by the WorkerMessenger
|
||||
// to retrieve the port given the apiObjectId part of the
|
||||
// mozIExtensionAPIRequest sent from the ExtensionPort webidl.
|
||||
api.portId = this.portId;
|
||||
return api;
|
||||
}
|
||||
}
|
||||
|
||||
defineLazyGetter(WorkerPort.prototype, "api", function() {
|
||||
// No need to clone the API object for the worker, because it runs
|
||||
// on a different JSRuntime and doesn't have direct access to this
|
||||
// object.
|
||||
return this.getAPI();
|
||||
});
|
||||
|
||||
/**
|
||||
* A Messenger subclass specialized for the background service worker.
|
||||
*/
|
||||
class WorkerMessenger extends Messenger {
|
||||
constructor(context) {
|
||||
const { viewType, contextId } = context;
|
||||
if (viewType !== "background_worker") {
|
||||
throw new Error(
|
||||
`Unexpected viewType "${viewType}" on context ${contextId}`
|
||||
);
|
||||
}
|
||||
|
||||
super(context);
|
||||
|
||||
// Used by WebIDL API requests to get a port instance given the apiObjectId
|
||||
// received in the API request coming from the ExtensionPort instance
|
||||
// returned in the thread where the request was originating from.
|
||||
this.portsById = new Map();
|
||||
this.context.callOnClose(this);
|
||||
}
|
||||
|
||||
initEventManagers() {
|
||||
const { context } = this;
|
||||
this.onConnect = new WorkerRuntimePortEvent(context, "runtime.onConnect");
|
||||
this.onConnectEx = new WorkerRuntimePortEvent(
|
||||
context,
|
||||
"runtime.onConnectExternal"
|
||||
);
|
||||
this.onMessage = new WorkerMessageEvent(this.context, "runtime.onMessage");
|
||||
this.onMessageEx = new WorkerMessageEvent(
|
||||
context,
|
||||
"runtime.onMessageExternal"
|
||||
);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.portsById.clear();
|
||||
}
|
||||
|
||||
getPortById(portId) {
|
||||
return this.portsById.get(portId);
|
||||
}
|
||||
|
||||
connect({ name, native, ...args }) {
|
||||
let portId = getUniqueId();
|
||||
let port = new WorkerPort(this.context, portId, name, !!native);
|
||||
this.conduit
|
||||
.queryPortConnect({ portId, name, native, ...args })
|
||||
.catch(error => port.recvPortDisconnect({ error }));
|
||||
this.portsById.set(`${portId}`, port);
|
||||
// Extension worker calls this method through the WebIDL bindings,
|
||||
// and the Port instance returned by the runtime.connect/connectNative
|
||||
// methods will be an instance of ExtensionPort webidl interface based
|
||||
// on the ExtensionPortDescriptor dictionary returned by this method.
|
||||
return { portId, name };
|
||||
}
|
||||
|
||||
recvPortConnect({ extensionId, portId, name, sender }) {
|
||||
let event = sender.id === extensionId ? this.onConnect : this.onConnectEx;
|
||||
if (this.context.active && event.fires.size) {
|
||||
let port = new WorkerPort(this.context, portId, name, false, sender);
|
||||
this.portsById.set(`${port.portId}`, port);
|
||||
return event.emit(port).length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* APIImplementation subclass specialized for handling mozIExtensionAPIRequests
|
||||
* originated from webidl bindings.
|
||||
*
|
||||
* Provides a createListenerForAPIRequest method which is used by
|
||||
* WebIDLChildAPIManager to retrieve an API event specific wrapper
|
||||
* for the mozIExtensionEventListener for the API events that needs
|
||||
* special handling (e.g. runtime.onConnect).
|
||||
*
|
||||
* createListenerForAPIRequest delegates to the API event the creation
|
||||
* of the special event listener wrappers, the EventManager api objects
|
||||
* for the events that needs special wrapper are expected to provide
|
||||
* a method with the same name.
|
||||
*/
|
||||
class ChildLocalWebIDLAPIImplementation extends ChildLocalAPIImplementation {
|
||||
constructor(pathObj, namespace, name, childApiManager) {
|
||||
super(pathObj, namespace, name, childApiManager);
|
||||
this.childApiManager = childApiManager;
|
||||
}
|
||||
|
||||
createListenerForAPIRequest(request) {
|
||||
return this.pathObj[this.name].createListenerForAPIRequest?.(request);
|
||||
}
|
||||
|
||||
setProperty() {
|
||||
// mozIExtensionAPIRequest doesn't support this requestType at the moment,
|
||||
// setting a pref would just replace the previous value on the wrapper
|
||||
// object living in the owner thread.
|
||||
// To be implemented if we have an actual use case where that is needed.
|
||||
throw new Error("Unexpected call to setProperty");
|
||||
}
|
||||
|
||||
hasListener(listener) {
|
||||
// hasListener is implemented in C++ by ExtensionEventManager, and so
|
||||
// a call to this method is unexpected.
|
||||
throw new Error("Unexpected call to hasListener");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* APIImplementation subclass specialized for handling API requests related
|
||||
* to an API Object type.
|
||||
*
|
||||
* Retrieving the apiObject instance is delegated internally to the
|
||||
* ExtensionAPI subclass that implements the request apiNamespace,
|
||||
* through an optional getAPIObjectForRequest method expected to be
|
||||
* available on the ExtensionAPI class.
|
||||
*/
|
||||
class ChildWebIDLObjectTypeImplementation extends ChildLocalWebIDLAPIImplementation {
|
||||
constructor(request, childApiManager) {
|
||||
const { apiNamespace, apiName, apiObjectType, apiObjectId } = request;
|
||||
const api = childApiManager.getExtensionAPIInstance(apiNamespace);
|
||||
const pathObj = api.getAPIObjectForRequest?.(
|
||||
childApiManager.context,
|
||||
request
|
||||
);
|
||||
if (!pathObj) {
|
||||
throw new Error(`apiObject instance not found for ${request}`);
|
||||
}
|
||||
super(pathObj, apiNamespace, apiName, childApiManager);
|
||||
this.fullname = `${apiNamespace}.${apiObjectType}(${apiObjectId}).${apiName}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A ChildAPIManager subclass specialized for handling mozIExtensionAPIRequest
|
||||
* originated from the WebIDL bindings.
|
||||
*
|
||||
* Currently used only for the extension contexts related to the background
|
||||
* service worker.
|
||||
*/
|
||||
class WebIDLChildAPIManager extends ChildAPIManager {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
// Map<apiPathToEventString, WeakMap<nsIExtensionEventListener, Function>>
|
||||
//
|
||||
// apiPathToEventString is a string that represents the full API path
|
||||
// related to the event name (e.g. "runtime.onConnect", or "runtime.Port.onMessage")
|
||||
this.eventListenerWrappers = new DefaultMap(() => new WeakMap());
|
||||
}
|
||||
|
||||
getImplementation(namespace, name) {
|
||||
this.apiCan.findAPIPath(`${namespace}.${name}`);
|
||||
let obj = this.apiCan.findAPIPath(namespace);
|
||||
|
||||
if (obj && name in obj) {
|
||||
return new ChildLocalWebIDLAPIImplementation(obj, namespace, name, this);
|
||||
}
|
||||
|
||||
return this.getFallbackImplementation(namespace, name);
|
||||
}
|
||||
|
||||
getImplementationForRequest(request) {
|
||||
const { apiNamespace, apiName, apiObjectType } = request;
|
||||
if (apiObjectType) {
|
||||
return new ChildWebIDLObjectTypeImplementation(request, this);
|
||||
}
|
||||
return this.getImplementation(apiNamespace, apiName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an ExtensionAPIRequest originated by the Extension APIs WebIDL bindings.
|
||||
*
|
||||
* @param {mozIExtensionAPIRequest} request
|
||||
* The object that represents the API request received
|
||||
* (including arguments, an event listener wrapper etc)
|
||||
*
|
||||
* @returns {mozIExtensionAPIRequestResult}
|
||||
* Result for the API request, either a value to be returned
|
||||
* (which has to be a value that can be structure cloned
|
||||
* if the request was originated from the worker thread) or
|
||||
* an error to raise to the extension code.
|
||||
*/
|
||||
handleWebIDLAPIRequest(request) {
|
||||
try {
|
||||
const impl = this.getImplementationForRequest(request);
|
||||
let result;
|
||||
this.context.withAPIRequest(request, () => {
|
||||
if (impl instanceof ProxyAPIImplementation) {
|
||||
result = this.handleForProxyAPIImplementation(request, impl);
|
||||
} else {
|
||||
result = this.callAPIImplementation(request, impl);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE,
|
||||
value: result,
|
||||
};
|
||||
} catch (error) {
|
||||
return this.handleExtensionError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an error raised while handling an API request,
|
||||
* into the expected mozIExtensionAPIRequestResult.
|
||||
*
|
||||
* @param {Error | WorkerExtensionError} error
|
||||
* @returns {mozIExtensionAPIRequestResult}
|
||||
*/
|
||||
|
||||
handleExtensionError(error) {
|
||||
// Propagate an extension error to the caller on the worker thread.
|
||||
if (error instanceof this.context.Error) {
|
||||
return {
|
||||
type: Ci.mozIExtensionAPIRequestResult.EXTENSION_ERROR,
|
||||
value: error,
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise just log it and throw a generic error.
|
||||
Cu.reportError(error);
|
||||
return {
|
||||
type: Ci.mozIExtensionAPIRequestResult.EXTENSION_ERROR,
|
||||
value: new this.context.Error("An unexpected error occurred"),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the given mozIExtensionAPIRequest using the given
|
||||
* APIImplementation instance.
|
||||
*
|
||||
* @param {mozIExtensionAPIRequest} request
|
||||
* @param {ChildLocalWebIDLAPIImplementation | ProxyAPIImplementation} impl
|
||||
* @returns {any}
|
||||
* @throws {Error | WorkerExtensionError}
|
||||
*/
|
||||
|
||||
callAPIImplementation(request, impl) {
|
||||
const { requestType, normalizedArgs } = request;
|
||||
|
||||
switch (requestType) {
|
||||
// TODO (Bug 1728328): follow up to take callAsyncFunction requireUserInput
|
||||
// parameter into account (until then callAsyncFunction, callFunction
|
||||
// and callFunctionNoReturn calls do not differ yet).
|
||||
case "callAsyncFunction":
|
||||
case "callFunction":
|
||||
case "callFunctionNoReturn":
|
||||
case "getProperty":
|
||||
return impl[requestType](normalizedArgs);
|
||||
case "addListener": {
|
||||
const listener = this.getOrCreateListenerWrapper(request, impl);
|
||||
impl.addListener(listener, normalizedArgs);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
case "removeListener": {
|
||||
const listener = this.getListenerWrapper(request);
|
||||
if (listener) {
|
||||
// Remove the previously added listener and forget the cleanup
|
||||
// observer previously passed to context.callOnClose.
|
||||
listener._callOnClose.close();
|
||||
this.contet.forgetOnclose(listener._callOnClose);
|
||||
this.forgetListenerWrapper(request);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
default:
|
||||
throw new Error(
|
||||
`Unexpected requestType ${requestType} while handling "${request}"`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the given mozIExtensionAPIRequest using the given
|
||||
* ProxyAPIImplementation instance.
|
||||
*
|
||||
* @param {mozIExtensionAPIRequest} request
|
||||
* @param {ProxyAPIImplementation} impl
|
||||
* @returns {any}
|
||||
* @throws {Error | WorkerExtensionError}
|
||||
*/
|
||||
|
||||
handleForProxyAPIImplementation(request, impl) {
|
||||
const { requestType } = request;
|
||||
switch (requestType) {
|
||||
case "callAsyncFunction":
|
||||
case "callFunctionNoReturn":
|
||||
case "addListener":
|
||||
case "removeListener":
|
||||
return this.callAPIImplementation(request, impl);
|
||||
default:
|
||||
// Any other request types (e.g. getProperty or callFunction) are
|
||||
// unexpected and so we raise a more detailed error to be logged
|
||||
// on the browser console (while the extension will receive the
|
||||
// generic "An unexpected error occurred" one).
|
||||
throw new Error(
|
||||
`Unexpected requestType ${requestType} while handling "${request}"`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getAPIPathForWebIDLRequest(request) {
|
||||
const { apiNamespace, apiName, apiObjectType } = request;
|
||||
if (apiObjectType) {
|
||||
return `${apiNamespace}.${apiObjectType}.${apiName}`;
|
||||
}
|
||||
|
||||
return `${apiNamespace}.${apiName}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an ExtensionAPI class instance given its namespace.
|
||||
*
|
||||
* @param {string} namespace
|
||||
* @returns {ExtensionAPI}
|
||||
*/
|
||||
getExtensionAPIInstance(namespace) {
|
||||
return this.apiCan.apis.get(namespace);
|
||||
}
|
||||
|
||||
getOrCreateListenerWrapper(request, impl) {
|
||||
let listener = this.getListenerWrapper(request);
|
||||
if (listener) {
|
||||
return listener;
|
||||
}
|
||||
|
||||
// Look for special wrappers that are needed for some API events
|
||||
// (e.g. runtime.onMessage/onConnect/...).
|
||||
if (impl instanceof ChildLocalWebIDLAPIImplementation) {
|
||||
listener = impl.createListenerForAPIRequest(request);
|
||||
}
|
||||
|
||||
const { eventListener } = request;
|
||||
listener =
|
||||
listener ??
|
||||
function(...args) {
|
||||
// Default wrapper just forwards all the arguments to the
|
||||
// extension callback (all arguments has to be structure cloneable
|
||||
// if the extension callback is on the worker thread).
|
||||
eventListener.callListener(args);
|
||||
};
|
||||
listener._callOnClose = {
|
||||
close: () => {
|
||||
this.eventListenerWrappers.delete(eventListener);
|
||||
// Failing to send the request to remove the listener in the parent
|
||||
// process shouldn't prevent the extension or context shutdown,
|
||||
// otherwise we would leak a WebExtensionPolicy instance.
|
||||
try {
|
||||
impl.removeListener(listener);
|
||||
} catch (err) {
|
||||
// Removing a listener when the extension context is being closed can
|
||||
// fail if the API is proxied to the parent process and the conduit
|
||||
// has been already closed, and so we ignore the error if we are not
|
||||
// processing a call proxied to the parent process.
|
||||
if (impl instanceof ChildLocalWebIDLAPIImplementation) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
this.storeListenerWrapper(request, listener);
|
||||
this.context.callOnClose(listener._callOnClose);
|
||||
return listener;
|
||||
}
|
||||
|
||||
getListenerWrapper(request) {
|
||||
const { eventListener } = request;
|
||||
if (!(eventListener instanceof Ci.mozIExtensionEventListener)) {
|
||||
throw new Error(`Unexpected eventListener type for request: ${request}`);
|
||||
}
|
||||
const apiPath = this.getAPIPathForWebIDLRequest(request);
|
||||
if (!this.eventListenerWrappers.has(apiPath)) {
|
||||
return undefined;
|
||||
}
|
||||
return this.eventListenerWrappers.get(apiPath).get(eventListener);
|
||||
}
|
||||
|
||||
storeListenerWrapper(request, listener) {
|
||||
const { eventListener } = request;
|
||||
if (!(eventListener instanceof Ci.mozIExtensionEventListener)) {
|
||||
throw new Error(`Missing eventListener for request: ${request}`);
|
||||
}
|
||||
const apiPath = this.getAPIPathForWebIDLRequest(request);
|
||||
this.eventListenerWrappers.get(apiPath).set(eventListener, listener);
|
||||
}
|
||||
|
||||
forgetListenerWrapper(request) {
|
||||
const { eventListener } = request;
|
||||
if (!(eventListener instanceof Ci.mozIExtensionEventListener)) {
|
||||
throw new Error(`Missing eventListener for request: ${request}`);
|
||||
}
|
||||
const apiPath = this.getAPIPathForWebIDLRequest(request);
|
||||
if (this.eventListenerWrappers.has(apiPath)) {
|
||||
this.eventListenerWrappers.get(apiPath).delete(eventListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ExtensionChild = {
|
||||
BrowserExtensionContent,
|
||||
ChildAPIManager,
|
||||
Messenger,
|
||||
WebIDLChildAPIManager,
|
||||
WorkerMessenger,
|
||||
};
|
||||
|
|
|
@ -489,18 +489,6 @@ class BaseContext {
|
|||
return this.extension.privateBrowsingAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the extension context is using the WebIDL bindings for the
|
||||
* WebExtensions APIs.
|
||||
* To be overridden in subclasses (e.g. WorkerContextChild) and to be
|
||||
* optionally used in ExtensionAPI classes to customize the behavior of the
|
||||
* API when the calls to the extension API are originated from the WebIDL
|
||||
* bindings.
|
||||
*/
|
||||
get useWebIDLBindings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
canAccessWindow(window) {
|
||||
return this.extension.canAccessWindow(window);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ const { ExtensionUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/ExtensionUtils.jsm"
|
||||
);
|
||||
|
||||
const { getInnerWindowID, getUniqueId, promiseEvent } = ExtensionUtils;
|
||||
const { getInnerWindowID, promiseEvent } = ExtensionUtils;
|
||||
|
||||
const {
|
||||
BaseContext,
|
||||
|
@ -54,12 +54,7 @@ const {
|
|||
defineLazyGetter,
|
||||
} = ExtensionCommon;
|
||||
|
||||
const {
|
||||
ChildAPIManager,
|
||||
Messenger,
|
||||
WebIDLChildAPIManager,
|
||||
WorkerMessenger,
|
||||
} = ExtensionChild;
|
||||
const { ChildAPIManager, Messenger } = ExtensionChild;
|
||||
|
||||
var ExtensionPageChild;
|
||||
|
||||
|
@ -156,168 +151,6 @@ var devtoolsAPIManager = new (class extends SchemaAPIManager {
|
|||
}
|
||||
})();
|
||||
|
||||
function getContextChildManagerGetter({ envType }) {
|
||||
return function() {
|
||||
let apiManager =
|
||||
envType === "devtools_parent"
|
||||
? devtoolsAPIManager
|
||||
: this.extension.apiManager;
|
||||
|
||||
apiManager.lazyInit();
|
||||
|
||||
let localApis = {};
|
||||
let can = new CanOfAPIs(this, apiManager, localApis);
|
||||
|
||||
const ChildAPIManagerClass = this.useWebIDLBindings
|
||||
? WebIDLChildAPIManager
|
||||
: ChildAPIManager;
|
||||
|
||||
let childManager = new ChildAPIManagerClass(
|
||||
this,
|
||||
this.messageManager,
|
||||
can,
|
||||
{
|
||||
envType,
|
||||
viewType: this.viewType,
|
||||
url: this.uri.spec,
|
||||
incognito: this.incognito,
|
||||
}
|
||||
);
|
||||
|
||||
this.callOnClose(childManager);
|
||||
|
||||
return childManager;
|
||||
};
|
||||
}
|
||||
|
||||
class WorkerContextChild extends BaseContext {
|
||||
/**
|
||||
* This WorkerContextChild represents an addon execution environment
|
||||
* that is running on the worker thread in an extension child process.
|
||||
*
|
||||
* @param {BrowserExtensionContent} extension This context's owner.
|
||||
* @param {object} params
|
||||
* @param {mozIExtensionServiceWorkerInfo} params.serviceWorkerInfo
|
||||
*/
|
||||
constructor(extension, { serviceWorkerInfo }) {
|
||||
if (
|
||||
!serviceWorkerInfo?.scriptURL ||
|
||||
!serviceWorkerInfo?.clientInfoId ||
|
||||
!serviceWorkerInfo?.principal
|
||||
) {
|
||||
throw new Error("Missing or invalid serviceWorkerInfo");
|
||||
}
|
||||
|
||||
super("addon_child", extension);
|
||||
this.viewType = "background_worker";
|
||||
this.uri = Services.io.newURI(serviceWorkerInfo.scriptURL);
|
||||
this.workerClientInfoId = serviceWorkerInfo.clientInfoId;
|
||||
this.workerPrincipal = serviceWorkerInfo.principal;
|
||||
this.incognito = serviceWorkerInfo.principal.privateBrowsingId > 0;
|
||||
|
||||
// A mozIExtensionAPIRequest being processed (set by the withAPIRequest
|
||||
// method while executing a given callable, can be optionally used by
|
||||
// the API implementation methods to access the mozIExtensionAPIRequest
|
||||
// being processed and customize their result if necessary to handle
|
||||
// requests originated by the webidl bindings).
|
||||
this.webidlAPIRequest = null;
|
||||
|
||||
// This context uses a plain object as a cloneScope (anyway the values
|
||||
// moved across thread are going to be automatically serialized/deserialized
|
||||
// as structure clone data, we may remove this if we are changing the
|
||||
// internals to not use the context.cloneScope).
|
||||
this.workerCloneScope = {
|
||||
Promise,
|
||||
// The instances of this Error constructor will be recognized by the
|
||||
// ExtensionAPIRequestHandler as errors that should be propagated to
|
||||
// the worker thread and received by extension code that originated
|
||||
// the API request.
|
||||
Error: ExtensionUtils.WorkerExtensionError,
|
||||
};
|
||||
}
|
||||
|
||||
openConduit(subject, address) {
|
||||
let proc = ChromeUtils.domProcessChild;
|
||||
let conduit = proc.getActor("ProcessConduits").openConduit(subject, {
|
||||
id: subject.id || getUniqueId(),
|
||||
extensionId: this.extension.id,
|
||||
envType: this.envType,
|
||||
workerScriptURL: this.uri.spec,
|
||||
...address,
|
||||
});
|
||||
this.callOnClose(conduit);
|
||||
conduit.setCloseCallback(() => {
|
||||
this.forgetOnClose(conduit);
|
||||
});
|
||||
return conduit;
|
||||
}
|
||||
|
||||
withAPIRequest(request, callable) {
|
||||
this.webidlAPIRequest = request;
|
||||
try {
|
||||
return callable();
|
||||
} finally {
|
||||
this.webidlAPIRequest = null;
|
||||
}
|
||||
}
|
||||
|
||||
getAPIRequest() {
|
||||
return this.webidlAPIRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the most recent stack frame from the WebIDL API request being
|
||||
* processed.
|
||||
*
|
||||
* @returns {SavedFrame?}
|
||||
*/
|
||||
getCaller() {
|
||||
return this.webidlAPIRequest?.callerSavedFrame;
|
||||
}
|
||||
|
||||
logActivity(type, name, data) {
|
||||
ExtensionActivityLogChild.log(this, type, name, data);
|
||||
}
|
||||
|
||||
get cloneScope() {
|
||||
return this.workerCloneScope;
|
||||
}
|
||||
|
||||
get principal() {
|
||||
return this.workerPrincipal;
|
||||
}
|
||||
|
||||
get tabId() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
get useWebIDLBindings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
this.unload();
|
||||
}
|
||||
|
||||
unload() {
|
||||
if (this.unloaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.unload();
|
||||
}
|
||||
}
|
||||
|
||||
defineLazyGetter(WorkerContextChild.prototype, "messenger", function() {
|
||||
return new WorkerMessenger(this);
|
||||
});
|
||||
|
||||
defineLazyGetter(
|
||||
WorkerContextChild.prototype,
|
||||
"childManager",
|
||||
getContextChildManagerGetter({ envType: "addon_parent" })
|
||||
);
|
||||
|
||||
class ExtensionBaseContextChild extends BaseContext {
|
||||
/**
|
||||
* This ExtensionBaseContextChild represents an addon execution environment
|
||||
|
@ -449,7 +282,23 @@ class ExtensionPageContextChild extends ExtensionBaseContextChild {
|
|||
defineLazyGetter(
|
||||
ExtensionPageContextChild.prototype,
|
||||
"childManager",
|
||||
getContextChildManagerGetter({ envType: "addon_parent" })
|
||||
function() {
|
||||
this.extension.apiManager.lazyInit();
|
||||
|
||||
let localApis = {};
|
||||
let can = new CanOfAPIs(this, this.extension.apiManager, localApis);
|
||||
|
||||
let childManager = new ChildAPIManager(this, this.messageManager, can, {
|
||||
envType: "addon_parent",
|
||||
viewType: this.viewType,
|
||||
url: this.uri.spec,
|
||||
incognito: this.incognito,
|
||||
});
|
||||
|
||||
this.callOnClose(childManager);
|
||||
|
||||
return childManager;
|
||||
}
|
||||
);
|
||||
|
||||
class DevToolsContextChild extends ExtensionBaseContextChild {
|
||||
|
@ -483,20 +332,29 @@ class DevToolsContextChild extends ExtensionBaseContextChild {
|
|||
}
|
||||
}
|
||||
|
||||
defineLazyGetter(
|
||||
DevToolsContextChild.prototype,
|
||||
"childManager",
|
||||
getContextChildManagerGetter({ envType: "devtools_parent" })
|
||||
);
|
||||
defineLazyGetter(DevToolsContextChild.prototype, "childManager", function() {
|
||||
devtoolsAPIManager.lazyInit();
|
||||
|
||||
let localApis = {};
|
||||
let can = new CanOfAPIs(this, devtoolsAPIManager, localApis);
|
||||
|
||||
let childManager = new ChildAPIManager(this, this.messageManager, can, {
|
||||
envType: "devtools_parent",
|
||||
viewType: this.viewType,
|
||||
url: this.uri.spec,
|
||||
incognito: this.incognito,
|
||||
});
|
||||
|
||||
this.callOnClose(childManager);
|
||||
|
||||
return childManager;
|
||||
});
|
||||
|
||||
ExtensionPageChild = {
|
||||
initialized: false,
|
||||
|
||||
// Map<innerWindowId, ExtensionPageContextChild>
|
||||
extensionContexts: new Map(),
|
||||
|
||||
// Map<workerClientInfoId, ExtensionWorkerContextChild>
|
||||
extensionWorkerContexts: new Map(),
|
||||
initialized: false,
|
||||
|
||||
apiManager,
|
||||
|
||||
|
@ -537,30 +395,6 @@ ExtensionPageChild = {
|
|||
});
|
||||
},
|
||||
|
||||
getContextForWorker(extension, serviceWorkerInfo) {
|
||||
this._init();
|
||||
|
||||
if (!serviceWorkerInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let context = this.extensionWorkerContexts.get(
|
||||
serviceWorkerInfo.clientInfoId
|
||||
);
|
||||
if (context && context.extension === extension) {
|
||||
return context;
|
||||
}
|
||||
|
||||
// Lazily create the context.
|
||||
if (!context) {
|
||||
context = new WorkerContextChild(extension, { serviceWorkerInfo });
|
||||
|
||||
this.extensionWorkerContexts.set(serviceWorkerInfo.clientInfoId, context);
|
||||
}
|
||||
|
||||
return context;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a privileged context at initial-document-element-inserted.
|
||||
*
|
||||
|
@ -636,12 +470,5 @@ ExtensionPageChild = {
|
|||
this.extensionContexts.delete(windowId);
|
||||
}
|
||||
}
|
||||
|
||||
for (let [workerClientInfoId, context] of this.extensionWorkerContexts) {
|
||||
if (context.extension.id == extensionId) {
|
||||
context.shutdown();
|
||||
this.extensionWorkerContexts.delete(workerClientInfoId);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -93,19 +93,6 @@ let StartupCache;
|
|||
|
||||
const global = this;
|
||||
|
||||
function verifyActorForContext(actor, context) {
|
||||
if (actor instanceof JSWindowActorParent) {
|
||||
let target = actor.browsingContext.top.embedderElement;
|
||||
if (context.parentMessageManager !== target.messageManager) {
|
||||
throw new Error("Got message on unexpected message manager");
|
||||
}
|
||||
} else if (actor instanceof JSProcessActorParent) {
|
||||
if (actor.manager.remoteType !== context.extension.remoteType) {
|
||||
throw new Error("Got message from unexpected process");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This object loads the ext-*.js scripts that define the extension API.
|
||||
let apiManager = new (class extends SchemaAPIManager {
|
||||
constructor() {
|
||||
|
@ -313,13 +300,10 @@ const ProxyMessenger = {
|
|||
url: source.url,
|
||||
};
|
||||
|
||||
if (source.actor instanceof JSWindowActorParent) {
|
||||
let browser = source.actor.browsingContext.top.embedderElement;
|
||||
let data =
|
||||
browser && apiManager.global.tabTracker.getBrowserData(browser);
|
||||
if (data?.tabId > 0) {
|
||||
sender.tab = extension.tabManager.get(data.tabId, null)?.convert();
|
||||
}
|
||||
let browser = source.actor.browsingContext.top.embedderElement;
|
||||
let data = browser && apiManager.global.tabTracker.getBrowserData(browser);
|
||||
if (data?.tabId > 0) {
|
||||
sender.tab = extension.tabManager.get(data.tabId, null)?.convert();
|
||||
}
|
||||
|
||||
return sender;
|
||||
|
@ -492,8 +476,7 @@ class ProxyContextParent extends BaseContext {
|
|||
// close the ProxyContext if the underlying message manager closes. This
|
||||
// message manager object may change when `xulBrowser` swaps docshells, e.g.
|
||||
// when a tab is moved to a different window.
|
||||
this.messageManagerProxy =
|
||||
xulBrowser && new MessageManagerProxy(xulBrowser);
|
||||
this.messageManagerProxy = new MessageManagerProxy(xulBrowser);
|
||||
|
||||
Object.defineProperty(this, "principal", {
|
||||
value: principal,
|
||||
|
@ -535,11 +518,11 @@ class ProxyContextParent extends BaseContext {
|
|||
}
|
||||
|
||||
get xulBrowser() {
|
||||
return this.messageManagerProxy?.eventTarget;
|
||||
return this.messageManagerProxy.eventTarget;
|
||||
}
|
||||
|
||||
get parentMessageManager() {
|
||||
return this.messageManagerProxy?.messageManager;
|
||||
return this.messageManagerProxy.messageManager;
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
|
@ -550,9 +533,7 @@ class ProxyContextParent extends BaseContext {
|
|||
if (this.unloaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.messageManagerProxy?.dispose();
|
||||
|
||||
this.messageManagerProxy.dispose();
|
||||
super.unload();
|
||||
apiManager.emit("proxy-context-unload", this);
|
||||
}
|
||||
|
@ -809,7 +790,7 @@ ParentAPIManager = {
|
|||
|
||||
recvCreateProxyContext(data, { actor, sender }) {
|
||||
let { envType, extensionId, childId, principal } = data;
|
||||
let target = actor.browsingContext?.top.embedderElement;
|
||||
let target = actor.browsingContext.top.embedderElement;
|
||||
|
||||
if (this.proxyContexts.has(childId)) {
|
||||
throw new Error(
|
||||
|
@ -828,34 +809,20 @@ ParentAPIManager = {
|
|||
throw new Error(`Bad sender context envType: ${sender.envType}`);
|
||||
}
|
||||
|
||||
if (actor instanceof JSWindowActorParent) {
|
||||
let processMessageManager =
|
||||
target.messageManager.processMessageManager ||
|
||||
Services.ppmm.getChildAt(0);
|
||||
let processMessageManager =
|
||||
target.messageManager.processMessageManager ||
|
||||
Services.ppmm.getChildAt(0);
|
||||
|
||||
if (!extension.parentMessageManager) {
|
||||
if (target.remoteType === extension.remoteType) {
|
||||
this.attachMessageManager(extension, processMessageManager);
|
||||
}
|
||||
if (!extension.parentMessageManager) {
|
||||
if (target.remoteType === extension.remoteType) {
|
||||
this.attachMessageManager(extension, processMessageManager);
|
||||
}
|
||||
}
|
||||
|
||||
if (processMessageManager !== extension.parentMessageManager) {
|
||||
throw new Error(
|
||||
"Attempt to create privileged extension parent from incorrect child process"
|
||||
);
|
||||
}
|
||||
} else if (actor instanceof JSProcessActorParent) {
|
||||
if (actor.manager.remoteType !== extension.remoteType) {
|
||||
throw new Error(
|
||||
"Attempt to create privileged extension parent from incorrect child process"
|
||||
);
|
||||
}
|
||||
|
||||
if (envType !== "addon_parent") {
|
||||
throw new Error(
|
||||
`Unexpected envType ${envType} on an extension process actor`
|
||||
);
|
||||
}
|
||||
if (processMessageManager !== extension.parentMessageManager) {
|
||||
throw new Error(
|
||||
"Attempt to create privileged extension parent from incorrect child process"
|
||||
);
|
||||
}
|
||||
|
||||
if (envType == "addon_parent") {
|
||||
|
@ -945,12 +912,13 @@ ParentAPIManager = {
|
|||
|
||||
async recvAPICall(data, { actor }) {
|
||||
let context = this.getContextById(data.childId);
|
||||
let target = actor.browsingContext?.top.embedderElement;
|
||||
|
||||
verifyActorForContext(actor, context);
|
||||
let target = actor.browsingContext.top.embedderElement;
|
||||
if (context.parentMessageManager !== target.messageManager) {
|
||||
throw new Error("Got message on unexpected message manager");
|
||||
}
|
||||
|
||||
let reply = result => {
|
||||
if (target && !context.parentMessageManager) {
|
||||
if (!context.parentMessageManager) {
|
||||
Services.console.logStringMessage(
|
||||
"Cannot send function call result: other side closed connection " +
|
||||
`(call data: ${uneval({ path: data.path, args: data.args })})`
|
||||
|
@ -1005,8 +973,10 @@ ParentAPIManager = {
|
|||
|
||||
async recvAddListener(data, { actor }) {
|
||||
let context = this.getContextById(data.childId);
|
||||
|
||||
verifyActorForContext(actor, context);
|
||||
let target = actor.browsingContext.top.embedderElement;
|
||||
if (context.parentMessageManager !== target.messageManager) {
|
||||
throw new Error("Got message on unexpected message manager");
|
||||
}
|
||||
|
||||
let { childId, alreadyLogged = false } = data;
|
||||
let handlingUserInput = false;
|
||||
|
|
|
@ -23,7 +23,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
ExtensionCommon: "resource://gre/modules/ExtensionCommon.jsm",
|
||||
ExtensionContent: "resource://gre/modules/ExtensionContent.jsm",
|
||||
ExtensionPageChild: "resource://gre/modules/ExtensionPageChild.jsm",
|
||||
Schemas: "resource://gre/modules/Schemas.jsm",
|
||||
});
|
||||
|
||||
const { ExtensionUtils } = ChromeUtils.import(
|
||||
|
@ -277,11 +276,6 @@ ExtensionManager = {
|
|||
let policy = WebExtensionPolicy.getByID(data.id);
|
||||
if (policy) {
|
||||
if (extensions.has(policy)) {
|
||||
// Shutdown any remaining extension context if running in the
|
||||
// extension process.
|
||||
if (WebExtensionPolicy.isExtensionProcess) {
|
||||
ExtensionPageChild.shutdownExtension(data.id);
|
||||
}
|
||||
extensions.get(policy).shutdown();
|
||||
}
|
||||
|
||||
|
@ -402,95 +396,11 @@ var ExtensionProcessScript = {
|
|||
|
||||
var ExtensionAPIRequestHandler = {
|
||||
handleAPIRequest(policy, request) {
|
||||
try {
|
||||
let extension = extensions.get(policy);
|
||||
|
||||
if (!extension) {
|
||||
throw new Error(`Extension instance not found for addon ${policy.id}`);
|
||||
}
|
||||
|
||||
let context = this.getExtensionContextForAPIRequest({
|
||||
extension,
|
||||
request,
|
||||
});
|
||||
|
||||
// Add a property to the request object for the normalizedArgs.
|
||||
request.normalizedArgs = this.validateAndNormalizeRequestArgs({
|
||||
context,
|
||||
request,
|
||||
});
|
||||
|
||||
return context.childManager.handleWebIDLAPIRequest(request);
|
||||
} catch (error) {
|
||||
// Do not propagate errors that are not meant to be accessible to the
|
||||
// extension, report it to the console and just throw the generic
|
||||
// "An unexpected error occurred".
|
||||
Cu.reportError(error);
|
||||
return {
|
||||
type: Ci.mozIExtensionAPIRequestResult.EXTENSION_ERROR,
|
||||
value: new Error("An unexpected error occurred"),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
getExtensionContextForAPIRequest({ extension, request }) {
|
||||
let context;
|
||||
|
||||
if (request.window) {
|
||||
throw new Error(
|
||||
`Extension API request originated from an extension window are not yet supported`
|
||||
);
|
||||
} else if (request.serviceWorkerInfo) {
|
||||
context = ExtensionPageChild.getContextForWorker(
|
||||
extension,
|
||||
request.serviceWorkerInfo
|
||||
);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
`Extension context not found for the extension service worker`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
`Extension API request originated from an unsupported extension global`
|
||||
);
|
||||
}
|
||||
|
||||
if (!context.useWebIDLBindings) {
|
||||
const { viewType, contextId } = context;
|
||||
throw new Error(
|
||||
`Extension ${extension.id} context "${viewType}" ${contextId} does not support WebIDL bindings`
|
||||
);
|
||||
}
|
||||
|
||||
return context;
|
||||
},
|
||||
|
||||
validateAndNormalizeRequestArgs({ context, request }) {
|
||||
if (!Schemas.checkPermissions(request.apiNamespace, context.extension)) {
|
||||
throw new context.Error(
|
||||
`Not enough privileges to access ${request.apiNamespace}`
|
||||
);
|
||||
}
|
||||
if (request.requestType === "getProperty") {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (request.apiObjectType) {
|
||||
// skip parameter validation on request targeting an api object,
|
||||
// even the JS-based implementation of the API objects are not
|
||||
// going through the same kind of Schema based validation that
|
||||
// the API namespaces methods and events go through.
|
||||
//
|
||||
// TODO(Bug 1728535): validate and normalize also this request arguments
|
||||
// as a low priority follow up.
|
||||
return request.args;
|
||||
}
|
||||
|
||||
const { apiNamespace, apiName, args } = request;
|
||||
// Validate and normalize parameters, set the normalized args on the
|
||||
// mozIExtensionAPIRequest normalizedArgs property.
|
||||
return Schemas.checkParameters(context, apiNamespace, apiName, args);
|
||||
// TODO: to be actually implemented in the "part3" patches that follows,
|
||||
// this patch does only contain a placeholder method, which is
|
||||
// replaced with a mock in the set of unit tests defined in this
|
||||
// patch.
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -70,19 +70,6 @@ function filterStack(error) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* An Error subclass used to recognize the errors that should
|
||||
* to be forwarded to the worker thread and being accessible
|
||||
* to the extension worker script (vs. the errors that should be
|
||||
* only logged internally and raised to the worker script as
|
||||
* the generic unexpected error).
|
||||
*/
|
||||
class WorkerExtensionError extends DOMException {
|
||||
constructor(message) {
|
||||
super(message, "Error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to a WeakMap, but creates a new key with the given
|
||||
* constructor if one is not present.
|
||||
|
@ -353,5 +340,4 @@ var ExtensionUtils = {
|
|||
DefaultWeakMap,
|
||||
ExtensionError,
|
||||
LimitedSet,
|
||||
WorkerExtensionError,
|
||||
};
|
||||
|
|
|
@ -3581,14 +3581,6 @@ this.Schemas = {
|
|||
|
||||
_rootSchema: null,
|
||||
|
||||
// A weakmap for the validation Context class instances given an extension
|
||||
// context (keyed by the extensin context instance).
|
||||
// This is used instead of the InjectionContext for webIDL API validation
|
||||
// and normalization (see Schemas.checkParameters).
|
||||
paramsValidationContexts: new DefaultWeakMap(
|
||||
extContext => new Context(extContext)
|
||||
),
|
||||
|
||||
get rootSchema() {
|
||||
if (!this.initialized) {
|
||||
this.init();
|
||||
|
@ -3764,31 +3756,4 @@ this.Schemas = {
|
|||
normalize(obj, typeName, context) {
|
||||
return this.rootSchema.normalize(obj, typeName, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate and normalize the arguments for an API request originated
|
||||
* from the webIDL API bindings.
|
||||
*
|
||||
* This provides for calls originating through WebIDL the parameters
|
||||
* validation and normalization guarantees that the ext-APINAMESPACE.js
|
||||
* scripts expects (what InjectionContext does for the regular bindings).
|
||||
*
|
||||
* @param {object} extContext
|
||||
* @param {string} apiNamespace
|
||||
* @param {string} apiName
|
||||
* @param {Array<any>} args
|
||||
*
|
||||
* @returns {Array<any>} Normalized arguments array.
|
||||
*/
|
||||
checkParameters(extContext, apiNamespace, apiName, args) {
|
||||
const apiSchema = this.getNamespace(apiNamespace)?.get(apiName);
|
||||
if (!apiSchema) {
|
||||
throw new Error(`API Schema not found for ${apiNamespace}.${apiName}`);
|
||||
}
|
||||
|
||||
return apiSchema.checkParameters(
|
||||
args,
|
||||
this.paramsValidationContexts.get(extContext)
|
||||
);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -91,16 +91,4 @@ this.runtime = class extends ExtensionAPI {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
getAPIObjectForRequest(context, request) {
|
||||
if (request.apiObjectType === "Port") {
|
||||
const port = context.messenger.getPortById(request.apiObjectId);
|
||||
if (!port) {
|
||||
throw new Error(`Port API object not found: ${request}`);
|
||||
}
|
||||
return port.api;
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected apiObjectType: ${request}`);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -92,58 +92,23 @@ this.test = class extends ExtensionAPI {
|
|||
getAPI(context) {
|
||||
const { extension } = context;
|
||||
|
||||
function getStack(savedFrame = null) {
|
||||
if (savedFrame) {
|
||||
return ChromeUtils.createError("", savedFrame).stack.replace(
|
||||
/^/gm,
|
||||
" "
|
||||
);
|
||||
}
|
||||
function getStack() {
|
||||
return new context.Error().stack.replace(/^/gm, " ");
|
||||
}
|
||||
|
||||
function assertTrue(value, msg) {
|
||||
extension.emit(
|
||||
"test-result",
|
||||
Boolean(value),
|
||||
String(msg),
|
||||
getStack(context.getCaller())
|
||||
);
|
||||
extension.emit("test-result", Boolean(value), String(msg), getStack());
|
||||
}
|
||||
|
||||
class TestEventManager extends EventManager {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
// A map to keep track of the listeners wrappers being added in
|
||||
// addListener (the wrapper will be needed to be able to remove
|
||||
// the listener from this EventManager instance if the extension
|
||||
// does call test.onMessage.removeListener).
|
||||
this._listenerWrappers = new Map();
|
||||
context.callOnClose({
|
||||
close: () => this._listenerWrappers.clear(),
|
||||
});
|
||||
}
|
||||
|
||||
addListener(callback, ...args) {
|
||||
const listenerWrapper = function(...args) {
|
||||
super.addListener(function(...args) {
|
||||
try {
|
||||
callback.call(this, ...args);
|
||||
} catch (e) {
|
||||
assertTrue(false, `${e}\n${e.stack}`);
|
||||
}
|
||||
};
|
||||
super.addListener(listenerWrapper, ...args);
|
||||
this._listenerWrappers.set(callback, listenerWrapper);
|
||||
}
|
||||
|
||||
removeListener(callback) {
|
||||
if (!this._listenerWrappers.has(callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.removeListener(this._listenerWrappers.get(callback));
|
||||
this._listenerWrappers.delete(callback);
|
||||
}, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,20 +139,15 @@ this.test = class extends ExtensionAPI {
|
|||
},
|
||||
|
||||
notifyPass(msg) {
|
||||
extension.emit("test-done", true, msg, getStack(context.getCaller()));
|
||||
extension.emit("test-done", true, msg, getStack());
|
||||
},
|
||||
|
||||
notifyFail(msg) {
|
||||
extension.emit(
|
||||
"test-done",
|
||||
false,
|
||||
msg,
|
||||
getStack(context.getCaller())
|
||||
);
|
||||
extension.emit("test-done", false, msg, getStack());
|
||||
},
|
||||
|
||||
log(msg) {
|
||||
extension.emit("test-log", true, msg, getStack(context.getCaller()));
|
||||
extension.emit("test-log", true, msg, getStack());
|
||||
},
|
||||
|
||||
fail(msg) {
|
||||
|
@ -221,7 +181,7 @@ this.test = class extends ExtensionAPI {
|
|||
String(msg),
|
||||
expected,
|
||||
actual,
|
||||
getStack(context.getCaller())
|
||||
getStack()
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
@ -32,10 +32,6 @@ interface mozIExtensionListenerCallOptions : nsISupports
|
|||
// if apiObjectType is RUNTIME_PORT).
|
||||
readonly attribute jsval apiObjectDescriptor;
|
||||
|
||||
// An optional boolean to be set to true if the api object should be
|
||||
// prepended to the rest of the call arguments (by default it is appended).
|
||||
readonly attribute bool apiObjectPrepended;
|
||||
|
||||
cenum CallbackType: 8 {
|
||||
// Default: no callback argument is passed to the call to the event listener.
|
||||
CALLBACK_NONE,
|
||||
|
@ -97,13 +93,6 @@ interface mozIExtensionAPIRequest : nsISupports
|
|||
// An array of API call arguments.
|
||||
[implicit_jscontext] readonly attribute jsval args;
|
||||
|
||||
// A property to store on the request objects the arguments normalized
|
||||
// based on the API jsonschema, so that they are being propagated along
|
||||
// with the API request object.
|
||||
// TODO: change this attribute to a readonly attribute if we moved
|
||||
// the parameters validation and normalization to the C++ layer.
|
||||
[implicit_jscontext] attribute jsval normalizedArgs;
|
||||
|
||||
// The caller SavedFrame (only set for calls originated off of the main thread
|
||||
// from a service worker).
|
||||
[implicit_jscontext] readonly attribute jsval callerSavedFrame;
|
||||
|
|
|
@ -121,49 +121,12 @@ class BackgroundWorker {
|
|||
}
|
||||
|
||||
async build() {
|
||||
const { extension } = this;
|
||||
|
||||
try {
|
||||
// TODO(Bug 17228327): follow up to spawn the active worker for a previously installed
|
||||
// background service worker.
|
||||
const regInfo = await serviceWorkerManager.registerForAddonPrincipal(
|
||||
this.extension.principal
|
||||
);
|
||||
this.registrationInfo = regInfo.QueryInterface(
|
||||
Ci.nsIServiceWorkerRegistrationInfo
|
||||
);
|
||||
|
||||
// TODO(bug 17228326): wait for worker context to be loaded (as we currently do
|
||||
// for the delayed background page).
|
||||
await this.waitForActiveWorker();
|
||||
} catch (e) {
|
||||
// Extension may be shutting down before the background worker has registered or
|
||||
// loaded.
|
||||
Cu.reportError(e);
|
||||
|
||||
if (extension.persistentListeners) {
|
||||
EventManager.clearPrimedListeners(this.extension, false);
|
||||
}
|
||||
|
||||
// TODO(bug 17228326): rename this to "background-script-aborted".
|
||||
extension.emit("background-page-aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(bug 17228326): wait for worker context to be loaded and
|
||||
// wait for all persistent event listeners registered by the worker
|
||||
// script to be handled (as we currently do for the delayed background
|
||||
// page).
|
||||
|
||||
if (extension.persistentListeners) {
|
||||
// |this.extension| may be null if the extension was shut down.
|
||||
// In that case, we still want to clear the primed listeners,
|
||||
// but not update the persistent listeners in the startupData.
|
||||
EventManager.clearPrimedListeners(extension, !!this.extension);
|
||||
}
|
||||
|
||||
// TODO(bug 17228326): rename this to "background-script-started".
|
||||
extension.emit("background-page-started");
|
||||
const regInfo = await serviceWorkerManager.registerForAddonPrincipal(
|
||||
this.extension.principal
|
||||
);
|
||||
this.registrationInfo = regInfo.QueryInterface(
|
||||
Ci.nsIServiceWorkerRegistrationInfo
|
||||
);
|
||||
}
|
||||
|
||||
shutdown(isAppShutdown) {
|
||||
|
@ -172,53 +135,12 @@ class BackgroundWorker {
|
|||
// shutdown (in which case a previously registered service worker is expected to stay
|
||||
// active across browser restarts).
|
||||
// - when the extension has been uninstalled
|
||||
if (!isAppShutdown) {
|
||||
this.registrationInfo?.forceShutdown();
|
||||
if (!isAppShutdown && this.registrationInfo) {
|
||||
this.registrationInfo.forceShutdown();
|
||||
}
|
||||
|
||||
this.registrationInfo = null;
|
||||
}
|
||||
|
||||
waitForActiveWorker() {
|
||||
const { extension, registrationInfo } = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
const resolveOnActive = () => {
|
||||
if (
|
||||
registrationInfo.activeWorker?.state ===
|
||||
Ci.nsIServiceWorkerInfo.STATE_ACTIVATED
|
||||
) {
|
||||
resolve();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const rejectOnUnregistered = () => {
|
||||
if (registrationInfo.unregistered) {
|
||||
reject(
|
||||
new Error(
|
||||
`Background service worker unregistered for "${extension.policy.debugName}"`
|
||||
)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (resolveOnActive() || rejectOnUnregistered()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const listener = {
|
||||
onChange() {
|
||||
if (resolveOnActive() || rejectOnUnregistered()) {
|
||||
registrationInfo.removeListener(listener);
|
||||
}
|
||||
},
|
||||
};
|
||||
registrationInfo.addListener(listener);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.backgroundPage = class extends ExtensionAPI {
|
||||
|
|
|
@ -88,17 +88,6 @@ class TestWorkerWatcher extends EventEmitter {
|
|||
ChromeUtils.unregisterProcessActor(this.JS_ACTOR_NAME);
|
||||
}
|
||||
|
||||
getRegistration(extension) {
|
||||
const swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
|
||||
Ci.nsIServiceWorkerManager
|
||||
);
|
||||
|
||||
return swm.getRegistrationByPrincipal(
|
||||
extension.extension.principal,
|
||||
extension.extension.principal.spec
|
||||
);
|
||||
}
|
||||
|
||||
watchExtensionServiceWorker(extension) {
|
||||
// These events are emitted by TestWatchExtensionWorkersParent.
|
||||
const promiseWorkerSpawned = this.waitForEvent("worker-spawned", extension);
|
||||
|
@ -114,11 +103,6 @@ class TestWorkerWatcher extends EventEmitter {
|
|||
Services.prefs.clearUserPref("dom.serviceWorkers.idle_timeout");
|
||||
});
|
||||
Services.prefs.setIntPref("dom.serviceWorkers.idle_timeout", 0);
|
||||
const swReg = this.getRegistration(extension);
|
||||
// If the active worker is already active, we have to make sure the new value
|
||||
// set on the idle_timeout pref is picked up by ServiceWorkerPrivate::ResetIdleTimeout.
|
||||
swReg.activeWorker?.attachDebugger();
|
||||
swReg.activeWorker?.detachDebugger();
|
||||
return promiseWorkerTerminated;
|
||||
};
|
||||
|
||||
|
@ -232,7 +216,15 @@ add_task(
|
|||
"The extension service worker has been terminated as expected"
|
||||
);
|
||||
|
||||
const swReg = testWorkerWatcher.getRegistration(extension);
|
||||
const swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
|
||||
Ci.nsIServiceWorkerManager
|
||||
);
|
||||
|
||||
const swReg = swm.getRegistrationByPrincipal(
|
||||
extension.extension.principal,
|
||||
extension.extension.principal.spec
|
||||
);
|
||||
|
||||
ok(swReg, "Got a service worker registration");
|
||||
ok(swReg?.activeWorker, "Got an active worker");
|
||||
|
||||
|
|
|
@ -24,13 +24,11 @@ add_task(async function setup() {
|
|||
add_task(async function test_ext_context_does_have_webidl_bindings() {
|
||||
await runExtensionAPITest("should have a browser global object", {
|
||||
backgroundScript() {
|
||||
const { browser, chrome } = self;
|
||||
const { browser } = self;
|
||||
|
||||
return {
|
||||
hasExtensionAPI: !!browser,
|
||||
hasExtensionMockAPI: !!browser?.mockExtensionAPI,
|
||||
hasChromeCompatGlobal: !!chrome,
|
||||
hasChromeMockAPI: !!chrome?.mockExtensionAPI,
|
||||
};
|
||||
},
|
||||
assertResults({ testResult, testError }) {
|
||||
|
@ -40,8 +38,6 @@ add_task(async function test_ext_context_does_have_webidl_bindings() {
|
|||
{
|
||||
hasExtensionAPI: true,
|
||||
hasExtensionMockAPI: true,
|
||||
hasChromeCompatGlobal: true,
|
||||
hasChromeMockAPI: true,
|
||||
},
|
||||
"browser and browser.test WebIDL API bindings found"
|
||||
);
|
||||
|
|
|
@ -1,401 +0,0 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
AddonTestUtils.init(this);
|
||||
AddonTestUtils.createAppInfo(
|
||||
"xpcshell@tests.mozilla.org",
|
||||
"XPCShell",
|
||||
"1",
|
||||
"42"
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await AddonTestUtils.promiseStartupManager();
|
||||
// Ensure that the profile-after-change message has been notified,
|
||||
// so that ServiceWokerRegistrar is going to be initialized.
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"profile-after-change",
|
||||
"force-serviceworkerrestart-init"
|
||||
);
|
||||
});
|
||||
|
||||
// Verify ExtensionAPIRequestHandler handling API requests for
|
||||
// an ext-*.js API module running in the local process
|
||||
// (toolkit/components/extensions/child/ext-test.js).
|
||||
add_task(async function test_sw_api_request_handling_local_process_api() {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
background: {
|
||||
service_worker: "sw.js",
|
||||
},
|
||||
applications: { gecko: { id: "test-bg-sw@mochi.test" } },
|
||||
},
|
||||
files: {
|
||||
"page.html": "<!DOCTYPE html><body></body>",
|
||||
"sw.js": async function() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
browser.test.succeed("call to test.succeed");
|
||||
browser.test.assertTrue(true, "call to test.assertTrue");
|
||||
browser.test.assertFalse(false, "call to test.assertFalse");
|
||||
browser.test.notifyPass("test-completed");
|
||||
});
|
||||
browser.test.sendMessage("bgsw-ready");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("bgsw-ready");
|
||||
extension.sendMessage("test-message-ok");
|
||||
await extension.awaitFinish();
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
// Verify ExtensionAPIRequestHandler handling API requests for
|
||||
// an ext-*.js API module running in the main process
|
||||
// (toolkit/components/extensions/parent/ext-alarms.js).
|
||||
add_task(async function test_sw_api_request_handling_main_process_api() {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
background: {
|
||||
service_worker: "sw.js",
|
||||
},
|
||||
permissions: ["alarms"],
|
||||
applications: { gecko: { id: "test-bg-sw@mochi.test" } },
|
||||
},
|
||||
files: {
|
||||
"page.html": "<!DOCTYPE html><body></body>",
|
||||
"sw.js": async function() {
|
||||
browser.alarms.create("test-alarm", { when: Date.now() + 2000000 });
|
||||
const all = await browser.alarms.getAll();
|
||||
if (all.length === 1 && all[0].name === "test-alarm") {
|
||||
browser.test.succeed("Got the expected alarms");
|
||||
} else {
|
||||
browser.test.fail(
|
||||
`browser.alarms.create didn't create the expected alarm: ${JSON.stringify(
|
||||
all
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
browser.alarms.onAlarm.addListener(alarm => {
|
||||
if (alarm.name === "test-onAlarm") {
|
||||
browser.test.succeed("Got the expected onAlarm event");
|
||||
} else {
|
||||
browser.test.fail(`Got unexpected onAlarm event: ${alarm.name}`);
|
||||
}
|
||||
browser.test.sendMessage("test-completed");
|
||||
});
|
||||
|
||||
browser.alarms.create("test-onAlarm", { when: Date.now() + 1000 });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("test-completed");
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_sw_api_request_bgsw_runtime_onMessage() {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
background: {
|
||||
service_worker: "sw.js",
|
||||
},
|
||||
permissions: [],
|
||||
applications: { gecko: { id: "test-bg-sw-on-message@mochi.test" } },
|
||||
},
|
||||
files: {
|
||||
"page.html": '<!DOCTYPE html><script src="page.js"></script>',
|
||||
"page.js": async function() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg !== "extpage-send-message") {
|
||||
browser.test.fail(`Unexpected message received: ${msg}`);
|
||||
return;
|
||||
}
|
||||
browser.runtime.sendMessage("extpage-send-message");
|
||||
});
|
||||
},
|
||||
"sw.js": async function() {
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
browser.test.sendMessage("bgsw-on-message", msg);
|
||||
});
|
||||
const extURL = browser.runtime.getURL("/");
|
||||
browser.test.sendMessage("ext-url", extURL);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
const extURL = await extension.awaitMessage("ext-url");
|
||||
equal(
|
||||
extURL,
|
||||
`moz-extension://${extension.uuid}/`,
|
||||
"Got the expected extension url"
|
||||
);
|
||||
|
||||
const extPage = await ExtensionTestUtils.loadContentPage(
|
||||
`${extURL}/page.html`,
|
||||
{ extension }
|
||||
);
|
||||
extension.sendMessage("extpage-send-message");
|
||||
|
||||
const msg = await extension.awaitMessage("bgsw-on-message");
|
||||
equal(msg, "extpage-send-message", "Got the expected message");
|
||||
await extPage.close();
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_sw_api_request_bgsw_runtime_sendMessage() {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
background: {
|
||||
service_worker: "sw.js",
|
||||
},
|
||||
permissions: [],
|
||||
applications: { gecko: { id: "test-bg-sw-sendMessage@mochi.test" } },
|
||||
},
|
||||
files: {
|
||||
"page.html": '<!DOCTYPE html><script src="page.js"></script>',
|
||||
"page.js": async function() {
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
browser.test.sendMessage("extpage-on-message", msg);
|
||||
});
|
||||
|
||||
browser.test.sendMessage("extpage-ready");
|
||||
},
|
||||
"sw.js": async function() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg !== "bgsw-send-message") {
|
||||
browser.test.fail(`Unexpected message received: ${msg}`);
|
||||
return;
|
||||
}
|
||||
browser.runtime.sendMessage("bgsw-send-message");
|
||||
});
|
||||
const extURL = browser.runtime.getURL("/");
|
||||
browser.test.sendMessage("ext-url", extURL);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
const extURL = await extension.awaitMessage("ext-url");
|
||||
equal(
|
||||
extURL,
|
||||
`moz-extension://${extension.uuid}/`,
|
||||
"Got the expected extension url"
|
||||
);
|
||||
|
||||
const extPage = await ExtensionTestUtils.loadContentPage(
|
||||
`${extURL}/page.html`,
|
||||
{ extension }
|
||||
);
|
||||
await extension.awaitMessage("extpage-ready");
|
||||
extension.sendMessage("bgsw-send-message");
|
||||
|
||||
const msg = await extension.awaitMessage("extpage-on-message");
|
||||
equal(msg, "bgsw-send-message", "Got the expected message");
|
||||
await extPage.close();
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
// Verify ExtensionAPIRequestHandler handling API requests that
|
||||
// returns a runtinme.Port API object.
|
||||
add_task(async function test_sw_api_request_bgsw_connnect_runtime_port() {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
background: {
|
||||
service_worker: "sw.js",
|
||||
},
|
||||
permissions: [],
|
||||
applications: { gecko: { id: "test-bg-sw@mochi.test" } },
|
||||
},
|
||||
files: {
|
||||
"page.html": '<!DOCTYPE html><script src="page.js"></script>',
|
||||
"page.js": async function() {
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
browser.test.sendMessage("page-got-port-from-sw");
|
||||
port.postMessage("page-to-sw");
|
||||
});
|
||||
browser.test.sendMessage("page-waiting-port");
|
||||
},
|
||||
"sw.js": async function() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg !== "connect-port") {
|
||||
return;
|
||||
}
|
||||
const port = browser.runtime.connect();
|
||||
if (!port) {
|
||||
browser.test.fail("Got an undefined port");
|
||||
}
|
||||
port.onMessage.addListener((msg, portArgument) => {
|
||||
browser.test.assertTrue(
|
||||
port === portArgument,
|
||||
"Got the expected runtime.Port instance"
|
||||
);
|
||||
browser.test.sendMessage("test-done", msg);
|
||||
});
|
||||
browser.test.sendMessage("sw-waiting-port-message");
|
||||
});
|
||||
|
||||
const portWithError = browser.runtime.connect();
|
||||
portWithError.onDisconnect.addListener(() => {
|
||||
const portError = portWithError.error;
|
||||
browser.test.sendMessage("port-error", {
|
||||
isError: portError instanceof Error,
|
||||
message: portError?.message,
|
||||
});
|
||||
});
|
||||
|
||||
const extURL = browser.runtime.getURL("/");
|
||||
browser.test.sendMessage("ext-url", extURL);
|
||||
browser.test.sendMessage("ext-id", browser.runtime.id);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
const extURL = await extension.awaitMessage("ext-url");
|
||||
equal(
|
||||
extURL,
|
||||
`moz-extension://${extension.uuid}/`,
|
||||
"Got the expected extension url"
|
||||
);
|
||||
|
||||
const extId = await extension.awaitMessage("ext-id");
|
||||
equal(extId, extension.id, "Got the expected extension id");
|
||||
|
||||
const lastError = await extension.awaitMessage("port-error");
|
||||
Assert.deepEqual(
|
||||
lastError,
|
||||
{
|
||||
isError: true,
|
||||
message: "Could not establish connection. Receiving end does not exist.",
|
||||
},
|
||||
"Got the expected lastError value"
|
||||
);
|
||||
|
||||
const extPage = await ExtensionTestUtils.loadContentPage(
|
||||
`${extURL}/page.html`,
|
||||
{ extension }
|
||||
);
|
||||
await extension.awaitMessage("page-waiting-port");
|
||||
|
||||
info("bgsw connect port");
|
||||
extension.sendMessage("connect-port");
|
||||
await extension.awaitMessage("sw-waiting-port-message");
|
||||
info("bgsw waiting port message");
|
||||
await extension.awaitMessage("page-got-port-from-sw");
|
||||
info("page got port from sw, wait to receive event");
|
||||
const msg = await extension.awaitMessage("test-done");
|
||||
equal(msg, "page-to-sw", "Got the expected message");
|
||||
await extPage.close();
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
// Verify ExtensionAPIRequestHandler handling API events that should
|
||||
// get a runtinme.Port API object as an event argument.
|
||||
add_task(async function test_sw_api_request_bgsw_runtime_onConnect() {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
background: {
|
||||
service_worker: "sw.js",
|
||||
},
|
||||
permissions: [],
|
||||
applications: { gecko: { id: "test-bg-sw-onConnect@mochi.test" } },
|
||||
},
|
||||
files: {
|
||||
"page.html": '<!DOCTYPE html><script src="page.js"></script>',
|
||||
"page.js": async function() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg !== "connect-port") {
|
||||
return;
|
||||
}
|
||||
const port = browser.runtime.connect();
|
||||
port.onMessage.addListener(msg => {
|
||||
browser.test.sendMessage("test-done", msg);
|
||||
});
|
||||
browser.test.sendMessage("page-waiting-port-message");
|
||||
});
|
||||
},
|
||||
"sw.js": async function() {
|
||||
try {
|
||||
const extURL = browser.runtime.getURL("/");
|
||||
browser.test.sendMessage("ext-url", extURL);
|
||||
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
browser.test.sendMessage("bgsw-got-port-from-page");
|
||||
port.postMessage("sw-to-page");
|
||||
});
|
||||
browser.test.sendMessage("bgsw-waiting-port");
|
||||
} catch (err) {
|
||||
browser.test.fail(`Error on runtime.onConnect: ${err}`);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
const extURL = await extension.awaitMessage("ext-url");
|
||||
equal(
|
||||
extURL,
|
||||
`moz-extension://${extension.uuid}/`,
|
||||
"Got the expected extension url"
|
||||
);
|
||||
await extension.awaitMessage("bgsw-waiting-port");
|
||||
|
||||
const extPage = await ExtensionTestUtils.loadContentPage(
|
||||
`${extURL}/page.html`,
|
||||
{ extension }
|
||||
);
|
||||
info("ext page connect port");
|
||||
extension.sendMessage("connect-port");
|
||||
|
||||
await extension.awaitMessage("page-waiting-port-message");
|
||||
info("page waiting port message");
|
||||
await extension.awaitMessage("bgsw-got-port-from-page");
|
||||
info("bgsw got port from page, page wait to receive event");
|
||||
const msg = await extension.awaitMessage("test-done");
|
||||
equal(msg, "sw-to-page", "Got the expected message");
|
||||
await extPage.close();
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_sw_runtime_lastError() {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
background: {
|
||||
service_worker: "sw.js",
|
||||
},
|
||||
applications: { gecko: { id: "test-bg-sw@mochi.test" } },
|
||||
},
|
||||
files: {
|
||||
"page.html": "<!DOCTYPE html><body></body>",
|
||||
"sw.js": async function() {
|
||||
browser.runtime.sendMessage(() => {
|
||||
const lastError = browser.runtime.lastError;
|
||||
if (!(lastError instanceof Error)) {
|
||||
browser.test.fail(
|
||||
`lastError isn't an Error instance: ${lastError}`
|
||||
);
|
||||
}
|
||||
browser.test.sendMessage("test-lastError-completed");
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("test-lastError-completed");
|
||||
await extension.unload();
|
||||
});
|
|
@ -121,15 +121,6 @@ add_task(async function test_method_return_runtime_port() {
|
|||
});
|
||||
return;
|
||||
}
|
||||
} else if (
|
||||
request.requestType == "getProperty" &&
|
||||
request.apiObjectType == "Port" &&
|
||||
request.apiName == "sender"
|
||||
) {
|
||||
return {
|
||||
type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE,
|
||||
value: { id: "fake-sender-id-prop" },
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected request: ${request}`);
|
||||
|
@ -165,19 +156,9 @@ add_task(async function test_port_as_event_listener_eventListener_param() {
|
|||
"function",
|
||||
"port.disconnect method"
|
||||
);
|
||||
port.onMessage.addListener((msg, portArg) => {
|
||||
port.onMessage.addListener(msg => {
|
||||
if (msg === "test-done") {
|
||||
testLog("Got a port.onMessage event");
|
||||
testAsserts.equal(
|
||||
portArg?.name,
|
||||
"a-port-name-2",
|
||||
"Got port as last argument"
|
||||
);
|
||||
testAsserts.equal(
|
||||
portArg === port,
|
||||
true,
|
||||
"Got the same port instance as expected"
|
||||
);
|
||||
resolve();
|
||||
} else {
|
||||
reject(
|
||||
|
@ -202,10 +183,9 @@ add_task(async function test_port_as_event_listener_eventListener_param() {
|
|||
request.requestType == "addListener" &&
|
||||
request.apiName == "onTestEvent"
|
||||
) {
|
||||
request.eventListener.callListener(["arg0", "arg1"], {
|
||||
request.eventListener.callListener([], {
|
||||
apiObjectType: Ci.mozIExtensionListenerCallOptions.RUNTIME_PORT,
|
||||
apiObjectDescriptor: { portId: "port-id-2", name: "a-port-name-2" },
|
||||
apiObjectPrepended: true,
|
||||
});
|
||||
return;
|
||||
} else if (
|
||||
|
@ -213,10 +193,7 @@ add_task(async function test_port_as_event_listener_eventListener_param() {
|
|||
request.apiObjectType == "Port" &&
|
||||
request.apiObjectId == "port-id-2"
|
||||
) {
|
||||
request.eventListener.callListener(["test-done"], {
|
||||
apiObjectType: Ci.mozIExtensionListenerCallOptions.RUNTIME_PORT,
|
||||
apiObjectDescriptor: { portId: "port-id-2", name: "a-port-name-2" },
|
||||
});
|
||||
request.eventListener.callListener(["test-done"]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,4 +27,3 @@ skip-if = os == "android" && verify
|
|||
[test_ext_webidl_api.js]
|
||||
[test_ext_webidl_api_event_callback.js]
|
||||
[test_ext_webidl_runtime_port.js]
|
||||
[test_ext_webidl_api_request_handler.js]
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
|
||||
#include "{{ webidl_name }}.h"
|
||||
#include "ExtensionEventManager.h"
|
||||
|
||||
#include "mozilla/dom/{{ webidl_name }}Binding.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace extensions {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF({{ webidl_name }});
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE({{ webidl_name }})
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE({{ webidl_name }}, mGlobal, mExtensionBrowser
|
||||
/* TODO: add events properties if any */);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION({{ webidl_name }})
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
{{ webidl_name }}::{{ webidl_name }}(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser)
|
||||
: mGlobal(aGlobal), mExtensionBrowser(aExtensionBrowser) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mExtensionBrowser);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool {{ webidl_name }}::IsAllowed(JSContext* aCx, JSObject* aGlobal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject* {{ webidl_name }}::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return dom::{{ webidl_name }}_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsIGlobalObject* {{ webidl_name }}::GetParentObject() const { return mGlobal; }
|
||||
|
||||
/* TODO add implementation for the event manager getter if any.
|
||||
ExtensionEventManager* {{ webidl_name}}::OnEVENTNAME() {
|
||||
if (!mOnEVENTNAMEEventMgr) {
|
||||
mOnEVENTNAMEEventMgr = CreateEventManager(u"onEventName"_ns);
|
||||
}
|
||||
|
||||
return mOnEVENTNAMEEventMgr;
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
|
@ -1,73 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
|
||||
#ifndef mozilla_extensions_{{ webidl_name }}_h
|
||||
#define mozilla_extensions_{{ webidl_name }}_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "ExtensionAPIBase.h"
|
||||
#include "ExtensionBrowser.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class ExtensionEventManager;
|
||||
|
||||
class {{ webidl_name }} final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public ExtensionAPINamespace {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
// TODO: add RefPtr for the ExtensionEventManager instances if any.
|
||||
// RefPtr<ExtensionEventManager> mOnEVENTNAMEEventMgr;
|
||||
|
||||
~{{ webidl_name }}() = default;
|
||||
|
||||
public:
|
||||
{{ webidl_name }}(nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser);
|
||||
|
||||
// ExtensionAPIBase methods
|
||||
nsIGlobalObject* GetGlobalObject() const override { return mGlobal; }
|
||||
|
||||
ExtensionBrowser* GetExtensionBrowser() const override {
|
||||
return mExtensionBrowser;
|
||||
}
|
||||
|
||||
nsString GetAPINamespace() const override { return u"{{ api_namespace }}"_ns; }
|
||||
|
||||
// nsWrapperCache interface methods
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// DOM bindings methods
|
||||
static bool IsAllowed(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
nsIGlobalObject* GetParentObject() const;
|
||||
|
||||
// TODO: add method for the event manager objects if any.
|
||||
// ExtensionEventManager* OnEVENTNAME();
|
||||
|
||||
// TODO: add methods for the property getters if any.
|
||||
// void GetPROP_NAME(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS({{ webidl_name }})
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_extensions_{{ webidl_name }}_h
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT
|
||||
*
|
||||
* The content of this file has been generated based on the WebExtensions API
|
||||
* JSONSchema using the following command:
|
||||
*
|
||||
* export SCRIPT_DIR="toolkit/components/extensions/webidl-api"
|
||||
* mach python $SCRIPT_DIR/GenerateWebIDLBindings.py -- {{ api_namespace }}
|
||||
*
|
||||
* More info about generating webidl API bindings for WebExtensions API at:
|
||||
*
|
||||
* https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/webidl_bindings.html
|
||||
*/
|
||||
|
||||
/* 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/.
|
||||
*
|
||||
* You are granted a license to use, reproduce and create derivative works of
|
||||
* this document.
|
||||
*/
|
||||
{%+ if webidl_description_comment %}
|
||||
{{ webidl_description_comment }}
|
||||
{%- endif %}
|
||||
[Exposed=({{ webidl_exposed_attr }}), LegacyNoInterfaceObject]
|
||||
interface {{ webidl_name }} {
|
||||
{{- webidl_definition_body }}
|
||||
};
|
|
@ -11,11 +11,8 @@
|
|||
#include "ExtensionAPICallFunctionNoReturn.h"
|
||||
#include "ExtensionAPICallSyncFunction.h"
|
||||
#include "ExtensionAPIGetProperty.h"
|
||||
#include "ExtensionBrowser.h"
|
||||
#include "ExtensionEventManager.h"
|
||||
#include "ExtensionPort.h"
|
||||
|
||||
#include "mozilla/ConsoleReportCollector.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/SerializedStackHolder.h"
|
||||
#include "mozilla/dom/FunctionBinding.h"
|
||||
|
@ -31,14 +28,12 @@ NS_IMPL_ISUPPORTS0(ChromeCompatCallbackHandler)
|
|||
|
||||
// static
|
||||
void ChromeCompatCallbackHandler::Create(
|
||||
ExtensionBrowser* aExtensionBrowser, dom::Promise* aPromise,
|
||||
const RefPtr<dom::Function>& aCallback) {
|
||||
dom::Promise* aPromise, const RefPtr<dom::Function>& aCallback) {
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(aExtensionBrowser);
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
RefPtr<ChromeCompatCallbackHandler> handler =
|
||||
new ChromeCompatCallbackHandler(aExtensionBrowser, aCallback);
|
||||
new ChromeCompatCallbackHandler(aCallback);
|
||||
|
||||
aPromise->AppendNativeHandler(handler);
|
||||
}
|
||||
|
@ -57,37 +52,7 @@ void ChromeCompatCallbackHandler::RejectedCallback(
|
|||
// Call the chrome-compatible callback without any parameter, the errors
|
||||
// isn't passed to the callback as a parameter but the extension will be
|
||||
// able to retrieve it from chrome.runtime.lastError.
|
||||
mExtensionBrowser->SetLastError(aValue);
|
||||
MOZ_KnownLive(mCallback)->Call({}, &retval, rv);
|
||||
if (mExtensionBrowser->ClearLastError()) {
|
||||
ReportUncheckedLastError(aCx, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
void ChromeCompatCallbackHandler::ReportUncheckedLastError(
|
||||
JSContext* aCx, JS::Handle<JS::Value> aValue) {
|
||||
nsCString sourceSpec;
|
||||
uint32_t line = 0;
|
||||
uint32_t column = 0;
|
||||
nsString valueString;
|
||||
|
||||
nsContentUtils::ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column,
|
||||
valueString);
|
||||
|
||||
nsTArray<nsString> params;
|
||||
params.AppendElement(valueString);
|
||||
|
||||
RefPtr<ConsoleReportCollector> reporter = new ConsoleReportCollector();
|
||||
reporter->AddConsoleReport(nsIScriptError::errorFlag, "content javascript"_ns,
|
||||
nsContentUtils::eDOM_PROPERTIES, sourceSpec, line,
|
||||
column, "WebExtensionUncheckedLastError"_ns,
|
||||
params);
|
||||
|
||||
dom::WorkerPrivate* workerPrivate = dom::GetWorkerPrivateFromContext(aCx);
|
||||
RefPtr<Runnable> r = NS_NewRunnableFunction(
|
||||
"ChromeCompatCallbackHandler::ReportUncheckedLastError",
|
||||
[reporter]() { reporter->FlushReportsToConsole(0); });
|
||||
workerPrivate->DispatchToMainThread(r.forget());
|
||||
}
|
||||
|
||||
// WebExtensionStub methods shared between multiple API namespaces.
|
||||
|
@ -135,55 +100,6 @@ void ExtensionAPIBase::CallWebExtMethod(JSContext* aCx,
|
|||
}
|
||||
}
|
||||
|
||||
void ExtensionAPIBase::CallWebExtMethodReturnsString(
|
||||
JSContext* aCx, const nsAString& aApiMethod,
|
||||
const dom::Sequence<JS::Value>& aArgs, nsAString& aRetVal,
|
||||
ErrorResult& aRv) {
|
||||
JS::Rooted<JS::Value> retval(aCx);
|
||||
auto request = CallSyncFunction(aApiMethod);
|
||||
request->Run(GetGlobalObject(), aCx, aArgs, &retval, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!retval.isString())) {
|
||||
ThrowUnexpectedError(aCx, aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoJSString str;
|
||||
if (!str.init(aCx, retval.toString())) {
|
||||
JS_ClearPendingException(aCx);
|
||||
ThrowUnexpectedError(aCx, aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
aRetVal = str;
|
||||
}
|
||||
|
||||
already_AddRefed<ExtensionPort> ExtensionAPIBase::CallWebExtMethodReturnsPort(
|
||||
JSContext* aCx, const nsAString& aApiMethod,
|
||||
const dom::Sequence<JS::Value>& aArgs, ErrorResult& aRv) {
|
||||
JS::Rooted<JS::Value> apiResult(aCx);
|
||||
auto request = CallSyncFunction(aApiMethod);
|
||||
request->Run(GetGlobalObject(), aCx, aArgs, &apiResult, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IgnoredErrorResult rv;
|
||||
auto* extensionBrowser = GetExtensionBrowser();
|
||||
RefPtr<ExtensionPort> port = extensionBrowser->GetPort(apiResult, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
// ExtensionPort::Create doesn't throw the js exception with the generic
|
||||
// error message as the "api request forwarding" helper classes.
|
||||
ThrowUnexpectedError(aCx, aRv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return port.forget();
|
||||
}
|
||||
|
||||
void ExtensionAPIBase::CallWebExtMethodAsyncInternal(
|
||||
JSContext* aCx, const nsAString& aApiMethod,
|
||||
const dom::Sequence<JS::Value>& aArgs,
|
||||
|
@ -207,8 +123,7 @@ void ExtensionAPIBase::CallWebExtMethodAsyncInternal(
|
|||
// The async method has been called with the chrome-compatible callback
|
||||
// convention.
|
||||
if (aCallback) {
|
||||
ChromeCompatCallbackHandler::Create(GetExtensionBrowser(), domPromise,
|
||||
aCallback);
|
||||
ChromeCompatCallbackHandler::Create(domPromise, aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -252,52 +167,11 @@ void ExtensionAPIBase::CallWebExtMethodAsyncAmbiguous(
|
|||
|
||||
// ExtensionAPIBase - API Request helpers
|
||||
|
||||
void ExtensionAPIBase::GetWebExtPropertyAsString(const nsString& aPropertyName,
|
||||
dom::DOMString& aRetval) {
|
||||
IgnoredErrorResult rv;
|
||||
|
||||
dom::AutoJSAPI jsapi;
|
||||
auto* global = GetGlobalObject();
|
||||
|
||||
if (!jsapi.Init(global)) {
|
||||
NS_WARNING("GetWebExtPropertyAsString fail to init jsapi");
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::RootedValue retval(cx);
|
||||
|
||||
RefPtr<ExtensionAPIGetProperty> request = GetProperty(aPropertyName);
|
||||
request->Run(global, cx, &retval, rv);
|
||||
if (rv.Failed()) {
|
||||
NS_WARNING("GetWebExtPropertyAsString failure");
|
||||
return;
|
||||
}
|
||||
nsAutoJSString strRetval;
|
||||
if (!retval.isString() || !strRetval.init(cx, retval)) {
|
||||
NS_WARNING("GetWebExtPropertyAsString got a non string result");
|
||||
return;
|
||||
}
|
||||
aRetval.SetKnownLiveString(strRetval);
|
||||
}
|
||||
|
||||
void ExtensionAPIBase::GetWebExtPropertyAsJSValue(
|
||||
JSContext* aCx, const nsAString& aPropertyName,
|
||||
JS::MutableHandle<JS::Value> aRetval) {
|
||||
IgnoredErrorResult rv;
|
||||
RefPtr<ExtensionAPIGetProperty> request = GetProperty(aPropertyName);
|
||||
request->Run(GetGlobalObject(), aCx, aRetval, rv);
|
||||
if (rv.Failed()) {
|
||||
NS_WARNING("GetWebExtPropertyAsJSValue failure");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<ExtensionEventManager> ExtensionAPIBase::CreateEventManager(
|
||||
const nsAString& aEventName) {
|
||||
RefPtr<ExtensionEventManager> eventMgr = new ExtensionEventManager(
|
||||
GetGlobalObject(), GetExtensionBrowser(), GetAPINamespace(), aEventName,
|
||||
GetAPIObjectType(), GetAPIObjectId());
|
||||
GetGlobalObject(), GetAPINamespace(), aEventName, GetAPIObjectType(),
|
||||
GetAPIObjectId());
|
||||
return eventMgr.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,11 @@ class ExtensionAPICallFunctionNoReturn;
|
|||
class ExtensionAPICallSyncFunction;
|
||||
class ExtensionAPICallAsyncFunction;
|
||||
class ExtensionAPIGetProperty;
|
||||
class ExtensionBrowser;
|
||||
class ExtensionEventManager;
|
||||
class ExtensionPort;
|
||||
|
||||
class ExtensionAPIBase {
|
||||
protected:
|
||||
virtual nsIGlobalObject* GetGlobalObject() const = 0;
|
||||
virtual ExtensionBrowser* GetExtensionBrowser() const = 0;
|
||||
virtual nsString GetAPINamespace() const = 0;
|
||||
virtual nsString GetAPIObjectType() const = 0;
|
||||
virtual nsString GetAPIObjectId() const = 0;
|
||||
|
@ -73,15 +70,6 @@ class ExtensionAPIBase {
|
|||
JS::MutableHandle<JS::Value> aRetVal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void CallWebExtMethodReturnsString(
|
||||
JSContext* aCx, const nsAString& aApiMethod,
|
||||
const dom::Sequence<JS::Value>& aArgs, nsAString& aRetVal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual already_AddRefed<ExtensionPort> CallWebExtMethodReturnsPort(
|
||||
JSContext* aCx, const nsAString& aApiMethod,
|
||||
const dom::Sequence<JS::Value>& aArgs, ErrorResult& aRv);
|
||||
|
||||
virtual void CallWebExtMethodAsync(
|
||||
JSContext* aCx, const nsAString& aApiMethod,
|
||||
const dom::Sequence<JS::Value>& aArgs,
|
||||
|
@ -93,13 +81,6 @@ class ExtensionAPIBase {
|
|||
const dom::Sequence<JS::Value>& aArgs,
|
||||
JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv);
|
||||
|
||||
virtual void GetWebExtPropertyAsString(const nsString& aPropertyName,
|
||||
dom::DOMString& aRetval);
|
||||
|
||||
virtual void GetWebExtPropertyAsJSValue(JSContext* aCx,
|
||||
const nsAString& aPropertyName,
|
||||
JS::MutableHandle<JS::Value> aRetval);
|
||||
|
||||
// API Requests helpers.
|
||||
already_AddRefed<ExtensionEventManager> CreateEventManager(
|
||||
const nsAString& aEventName);
|
||||
|
@ -135,8 +116,7 @@ class ChromeCompatCallbackHandler final : public dom::PromiseNativeHandler {
|
|||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
static void Create(ExtensionBrowser* aExtensionBrowser,
|
||||
dom::Promise* aPromise,
|
||||
static void Create(dom::Promise* aPromise,
|
||||
const RefPtr<dom::Function>& aCallback);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void ResolvedCallback(
|
||||
|
@ -145,19 +125,14 @@ class ChromeCompatCallbackHandler final : public dom::PromiseNativeHandler {
|
|||
JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
private:
|
||||
ChromeCompatCallbackHandler(ExtensionBrowser* aExtensionBrowser,
|
||||
const RefPtr<dom::Function>& aCallback)
|
||||
: mCallback(aCallback), mExtensionBrowser(aExtensionBrowser) {
|
||||
explicit ChromeCompatCallbackHandler(const RefPtr<dom::Function>& aCallback)
|
||||
: mCallback(aCallback) {
|
||||
MOZ_ASSERT(aCallback);
|
||||
MOZ_ASSERT(aExtensionBrowser);
|
||||
}
|
||||
|
||||
~ChromeCompatCallbackHandler() = default;
|
||||
|
||||
void ReportUncheckedLastError(JSContext* aCx, JS::Handle<JS::Value> aValue);
|
||||
|
||||
RefPtr<dom::Function> mCallback;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
|
|
@ -62,7 +62,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ExtensionAPIRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArgs)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mNormalizedArgs)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
|
@ -71,7 +70,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ExtensionAPIRequest)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSWInfo)
|
||||
tmp->mStack.setUndefined();
|
||||
tmp->mArgs.setUndefined();
|
||||
tmp->mNormalizedArgs.setUndefined();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
ExtensionAPIRequest::ExtensionAPIRequest(
|
||||
|
@ -90,7 +88,6 @@ void ExtensionAPIRequest::Init(Maybe<dom::ClientInfo>& aSWClientInfo,
|
|||
mSWClientInfo = aSWClientInfo;
|
||||
mArgs.set(aRequestArgs);
|
||||
mStack.set(aCallerStack);
|
||||
mNormalizedArgs.setUndefined();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -185,22 +182,6 @@ ExtensionAPIRequest::GetArgs(JSContext* aCx,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExtensionAPIRequest::GetNormalizedArgs(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aRetval) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
aRetval.set(mNormalizedArgs);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExtensionAPIRequest::SetNormalizedArgs(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aNormalizedArgs) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mNormalizedArgs.set(aNormalizedArgs);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExtensionAPIRequest::GetCallerSavedFrame(
|
||||
JSContext* aCx, JS::MutableHandle<JS::Value> aSavedFrame) {
|
||||
|
|
|
@ -93,7 +93,6 @@ class ExtensionAPIRequest : public mozIExtensionAPIRequest {
|
|||
virtual ~ExtensionAPIRequest() {
|
||||
mSWClientInfo = Nothing();
|
||||
mArgs.setUndefined();
|
||||
mNormalizedArgs.setUndefined();
|
||||
mStack.setUndefined();
|
||||
mEventListener = nullptr;
|
||||
mozilla::DropJSObjects(this);
|
||||
|
@ -103,7 +102,6 @@ class ExtensionAPIRequest : public mozIExtensionAPIRequest {
|
|||
ExtensionAPIRequestTarget mRequestTarget;
|
||||
JS::Heap<JS::Value> mStack;
|
||||
JS::Heap<JS::Value> mArgs;
|
||||
JS::Heap<JS::Value> mNormalizedArgs;
|
||||
Maybe<dom::ClientInfo> mSWClientInfo;
|
||||
RefPtr<ExtensionServiceWorkerInfo> mSWInfo;
|
||||
|
||||
|
|
|
@ -533,12 +533,12 @@ bool RequestWorkerRunnable::ProcessHandlerResult(
|
|||
|
||||
ErrorResult rv;
|
||||
nsIGlobalObject* glob = xpc::CurrentNativeGlobal(aCx);
|
||||
RefPtr<dom::Promise> retPromise =
|
||||
already_AddRefed<dom::Promise> promise =
|
||||
dom::Promise::Resolve(glob, aCx, aRetval, rv);
|
||||
if (rv.Failed()) {
|
||||
return false;
|
||||
}
|
||||
retPromise->AppendNativeHandler(mPromiseProxy);
|
||||
promise.take()->AppendNativeHandler(mPromiseProxy);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
|
||||
#include "ExtensionAlarms.h"
|
||||
#include "ExtensionEventManager.h"
|
||||
|
||||
#include "mozilla/dom/ExtensionAlarmsBinding.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace extensions {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionAlarms);
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionAlarms)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ExtensionAlarms, mGlobal,
|
||||
mExtensionBrowser, mOnAlarmEventMgr);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionAlarms)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ExtensionAlarms::ExtensionAlarms(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser)
|
||||
: mGlobal(aGlobal), mExtensionBrowser(aExtensionBrowser) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mExtensionBrowser);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool ExtensionAlarms::IsAllowed(JSContext* aCx, JSObject* aGlobal) {
|
||||
// TODO(Bug 1725478): this API visibility should be gated by the "alarms"
|
||||
// permission.
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject* ExtensionAlarms::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return dom::ExtensionAlarms_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsIGlobalObject* ExtensionAlarms::GetParentObject() const { return mGlobal; }
|
||||
|
||||
ExtensionEventManager* ExtensionAlarms::OnAlarm() {
|
||||
if (!mOnAlarmEventMgr) {
|
||||
mOnAlarmEventMgr = CreateEventManager(u"onAlarm"_ns);
|
||||
}
|
||||
|
||||
return mOnAlarmEventMgr;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
|
@ -1,69 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
|
||||
#ifndef mozilla_extensions_ExtensionAlarms_h
|
||||
#define mozilla_extensions_ExtensionAlarms_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "ExtensionAPIBase.h"
|
||||
#include "ExtensionBrowser.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class ExtensionEventManager;
|
||||
|
||||
class ExtensionAlarms final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public ExtensionAPINamespace {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
RefPtr<ExtensionEventManager> mOnAlarmEventMgr;
|
||||
|
||||
~ExtensionAlarms() = default;
|
||||
|
||||
public:
|
||||
ExtensionAlarms(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser);
|
||||
|
||||
// ExtensionAPIBase methods
|
||||
nsIGlobalObject* GetGlobalObject() const override { return mGlobal; }
|
||||
|
||||
ExtensionBrowser* GetExtensionBrowser() const override {
|
||||
return mExtensionBrowser;
|
||||
}
|
||||
|
||||
nsString GetAPINamespace() const override { return u"alarms"_ns; }
|
||||
|
||||
// nsWrapperCache interface methods
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// DOM bindings methods
|
||||
static bool IsAllowed(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
nsIGlobalObject* GetParentObject() const;
|
||||
|
||||
ExtensionEventManager* OnAlarm();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionAlarms)
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_extensions_ExtensionAlarms_h
|
|
@ -7,51 +7,23 @@
|
|||
#include "ExtensionBrowser.h"
|
||||
|
||||
#include "mozilla/dom/ExtensionBrowserBinding.h"
|
||||
#include "mozilla/dom/ExtensionPortBinding.h" // ExtensionPortDescriptor
|
||||
#include "mozilla/dom/WorkerPrivate.h" // GetWorkerPrivateFromContext
|
||||
#include "mozilla/extensions/ExtensionAlarms.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h" // GetWorkerPrivateFromContext
|
||||
#include "mozilla/extensions/ExtensionMockAPI.h"
|
||||
#include "mozilla/extensions/ExtensionPort.h"
|
||||
#include "mozilla/extensions/ExtensionRuntime.h"
|
||||
#include "mozilla/extensions/ExtensionTest.h"
|
||||
#include "mozilla/extensions/WebExtensionPolicy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace extensions {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(ExtensionBrowser)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionBrowser)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionBrowser);
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionBrowser)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ExtensionBrowser, mGlobal,
|
||||
mExtensionMockAPI);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionBrowser)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ExtensionBrowser)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExtensionAlarms)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExtensionMockAPI)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExtensionRuntime)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExtensionTest)
|
||||
tmp->mLastError.setUndefined();
|
||||
tmp->mPortsLookup.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ExtensionBrowser)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExtensionAlarms)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExtensionMockAPI)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExtensionRuntime)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExtensionTest)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ExtensionBrowser)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLastError)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
ExtensionBrowser::ExtensionBrowser(nsIGlobalObject* aGlobal)
|
||||
: mGlobal(aGlobal) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
|
||||
|
@ -97,57 +69,6 @@ bool ExtensionAPIAllowed(JSContext* aCx, JSObject* aGlobal) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void ExtensionBrowser::SetLastError(JS::Handle<JS::Value> aLastError) {
|
||||
mLastError.set(aLastError);
|
||||
mCheckedLastError = false;
|
||||
}
|
||||
|
||||
void ExtensionBrowser::GetLastError(JS::MutableHandle<JS::Value> aRetVal) {
|
||||
aRetVal.set(mLastError);
|
||||
mCheckedLastError = true;
|
||||
}
|
||||
|
||||
bool ExtensionBrowser::ClearLastError() {
|
||||
bool shouldReport = !mCheckedLastError;
|
||||
mLastError.setUndefined();
|
||||
return shouldReport;
|
||||
}
|
||||
|
||||
already_AddRefed<ExtensionPort> ExtensionBrowser::GetPort(
|
||||
JS::Handle<JS::Value> aDescriptorValue, ErrorResult& aRv) {
|
||||
// Get a port descriptor from the js value got from the API request
|
||||
// handler.
|
||||
UniquePtr<dom::ExtensionPortDescriptor> portDescriptor =
|
||||
ExtensionPort::ToPortDescriptor(aDescriptorValue, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto portId = portDescriptor->mPortId;
|
||||
auto maybePort = mPortsLookup.MaybeGet(portId);
|
||||
if (maybePort.isSome() && maybePort.value().get()) {
|
||||
RefPtr<ExtensionPort> existingPort = maybePort.value().get();
|
||||
return existingPort.forget();
|
||||
}
|
||||
|
||||
RefPtr<ExtensionPort> newPort =
|
||||
ExtensionPort::Create(mGlobal, this, std::move(portDescriptor));
|
||||
mPortsLookup.InsertOrUpdate(portId, newPort);
|
||||
return newPort.forget();
|
||||
}
|
||||
|
||||
void ExtensionBrowser::ForgetReleasedPort(const nsAString& aPortId) {
|
||||
mPortsLookup.Remove(aPortId);
|
||||
}
|
||||
|
||||
ExtensionAlarms* ExtensionBrowser::GetExtensionAlarms() {
|
||||
if (!mExtensionAlarms) {
|
||||
mExtensionAlarms = new ExtensionAlarms(mGlobal, this);
|
||||
}
|
||||
|
||||
return mExtensionAlarms;
|
||||
}
|
||||
|
||||
ExtensionMockAPI* ExtensionBrowser::GetExtensionMockAPI() {
|
||||
if (!mExtensionMockAPI) {
|
||||
mExtensionMockAPI = new ExtensionMockAPI(mGlobal, this);
|
||||
|
@ -156,21 +77,5 @@ ExtensionMockAPI* ExtensionBrowser::GetExtensionMockAPI() {
|
|||
return mExtensionMockAPI;
|
||||
}
|
||||
|
||||
ExtensionRuntime* ExtensionBrowser::GetExtensionRuntime() {
|
||||
if (!mExtensionRuntime) {
|
||||
mExtensionRuntime = new ExtensionRuntime(mGlobal, this);
|
||||
}
|
||||
|
||||
return mExtensionRuntime;
|
||||
}
|
||||
|
||||
ExtensionTest* ExtensionBrowser::GetExtensionTest() {
|
||||
if (!mExtensionTest) {
|
||||
mExtensionTest = new ExtensionTest(mGlobal, this);
|
||||
}
|
||||
|
||||
return mExtensionTest;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -19,52 +19,19 @@ class ErrorResult;
|
|||
|
||||
namespace extensions {
|
||||
|
||||
class ExtensionAlarms;
|
||||
class ExtensionMockAPI;
|
||||
class ExtensionPort;
|
||||
class ExtensionRuntime;
|
||||
class ExtensionTest;
|
||||
|
||||
bool ExtensionAPIAllowed(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
class ExtensionBrowser final : public nsISupports, public nsWrapperCache {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
JS::Heap<JS::Value> mLastError;
|
||||
bool mCheckedLastError;
|
||||
RefPtr<ExtensionAlarms> mExtensionAlarms;
|
||||
RefPtr<ExtensionMockAPI> mExtensionMockAPI;
|
||||
RefPtr<ExtensionRuntime> mExtensionRuntime;
|
||||
RefPtr<ExtensionTest> mExtensionTest;
|
||||
nsTHashMap<nsStringHashKey, WeakPtr<ExtensionPort>> mPortsLookup;
|
||||
|
||||
~ExtensionBrowser() = default;
|
||||
|
||||
public:
|
||||
explicit ExtensionBrowser(nsIGlobalObject* aGlobal);
|
||||
|
||||
// Helpers used for the expected behavior of the browser.runtime.lastError
|
||||
// and browser.extension.lastError.
|
||||
void SetLastError(JS::Handle<JS::Value> aLastError);
|
||||
void GetLastError(JS::MutableHandle<JS::Value> aRetVal);
|
||||
// ClearLastError is used by ChromeCompatCallbackHandler::RejectedCallback
|
||||
// to clear the lastError property. When this method returns true the
|
||||
// caller will know that the error value wasn't checked by the callback and
|
||||
// should be reported to the console
|
||||
bool ClearLastError();
|
||||
|
||||
// Helpers used for the ExtensionPort.
|
||||
|
||||
// Get an ExtensionPort instance given its port descriptor (returns an
|
||||
// existing port if an instance is still tracked in the ports lookup table,
|
||||
// otherwise it creates a new one).
|
||||
already_AddRefed<ExtensionPort> GetPort(
|
||||
JS::Handle<JS::Value> aDescriptorValue, ErrorResult& aRv);
|
||||
|
||||
// Remove the entry for an ExtensionPort tracked in the ports lookup map
|
||||
// given its portId (called from the ExtensionPort destructor when the
|
||||
// instance is being released).
|
||||
void ForgetReleasedPort(const nsAString& aPortId);
|
||||
|
||||
// nsWrapperCache interface methods
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
@ -73,10 +40,7 @@ class ExtensionBrowser final : public nsISupports, public nsWrapperCache {
|
|||
|
||||
nsIGlobalObject* GetParentObject() const;
|
||||
|
||||
ExtensionAlarms* GetExtensionAlarms();
|
||||
ExtensionMockAPI* GetExtensionMockAPI();
|
||||
ExtensionRuntime* GetExtensionRuntime();
|
||||
ExtensionTest* GetExtensionTest();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionBrowser)
|
||||
|
|
|
@ -164,12 +164,11 @@ NS_IMPL_ISUPPORTS(ExtensionEventListener, mozIExtensionEventListener)
|
|||
|
||||
// static
|
||||
already_AddRefed<ExtensionEventListener> ExtensionEventListener::Create(
|
||||
nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser,
|
||||
dom::Function* aCallback, CleanupCallback&& aCleanupCallback,
|
||||
ErrorResult& aRv) {
|
||||
nsIGlobalObject* aGlobal, dom::Function* aCallback,
|
||||
CleanupCallback&& aCleanupCallback, ErrorResult& aRv) {
|
||||
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
|
||||
RefPtr<ExtensionEventListener> extCb =
|
||||
new ExtensionEventListener(aGlobal, aExtensionBrowser, aCallback);
|
||||
new ExtensionEventListener(aGlobal, aCallback);
|
||||
|
||||
auto* workerPrivate = dom::GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
@ -280,19 +279,11 @@ NS_IMETHODIMP ExtensionEventListener::CallListener(
|
|||
}
|
||||
|
||||
if (apiObjectType != APIObjectType::NONE) {
|
||||
bool prependArgument = false;
|
||||
aCallOptions->GetApiObjectPrepended(&prependArgument);
|
||||
// Prepend or append the apiObjectDescriptor data to the call arguments,
|
||||
// Prepend the apiObjectDescriptor data to the call arguments,
|
||||
// the worker runnable will convert that into an API object
|
||||
// instance on the worker thread.
|
||||
if (prependArgument) {
|
||||
if (!args.InsertElementAt(0, std::move(apiObjectDescriptor), fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else {
|
||||
if (!args.AppendElement(std::move(apiObjectDescriptor), fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!args.InsertElementAt(0, std::move(apiObjectDescriptor), fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,11 +335,6 @@ bool ExtensionListenerCallWorkerRunnable::WorkerRun(
|
|||
return true;
|
||||
}
|
||||
|
||||
RefPtr<ExtensionBrowser> extensionBrowser = mListener->GetExtensionBrowser();
|
||||
if (NS_WARN_IF(!extensionBrowser)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto fn = mListener->GetCallback();
|
||||
if (NS_WARN_IF(!fn)) {
|
||||
return true;
|
||||
|
@ -404,9 +390,7 @@ bool ExtensionListenerCallWorkerRunnable::WorkerRun(
|
|||
// one element.
|
||||
MOZ_ASSERT(!argsSequence.IsEmpty());
|
||||
|
||||
uint32_t apiObjectIdx = mAPIObjectPrepended ? 0 : argsSequence.Length() - 1;
|
||||
JS::Rooted<JS::Value> apiObjectDescriptor(
|
||||
aCx, argsSequence.ElementAt(apiObjectIdx));
|
||||
JS::Rooted<JS::Value> apiObjectDescriptor(aCx, argsSequence.ElementAt(0));
|
||||
JS::Rooted<JS::Value> apiObjectValue(aCx);
|
||||
|
||||
// We only expect the object type to be RUNTIME_PORT at the moment,
|
||||
|
@ -414,7 +398,7 @@ bool ExtensionListenerCallWorkerRunnable::WorkerRun(
|
|||
// some specific API may need.
|
||||
MOZ_ASSERT(mAPIObjectType == APIObjectType::RUNTIME_PORT);
|
||||
RefPtr<ExtensionPort> port =
|
||||
extensionBrowser->GetPort(apiObjectDescriptor, rv);
|
||||
ExtensionPort::Create(global, apiObjectDescriptor, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
retPromise->MaybeReject(rv.StealNSResult());
|
||||
return true;
|
||||
|
@ -425,7 +409,7 @@ bool ExtensionListenerCallWorkerRunnable::WorkerRun(
|
|||
return true;
|
||||
}
|
||||
|
||||
argsSequence.ReplaceElementAt(apiObjectIdx, apiObjectValue);
|
||||
argsSequence.ReplaceElementAt(0, apiObjectValue);
|
||||
}
|
||||
|
||||
// Create callback argument and append it to the call arguments.
|
||||
|
|
|
@ -46,9 +46,8 @@ class ExtensionEventListener final : public mozIExtensionEventListener {
|
|||
using CallbackType = ListenerCallOptions::CallbackType;
|
||||
|
||||
static already_AddRefed<ExtensionEventListener> Create(
|
||||
nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser,
|
||||
dom::Function* aCallback, CleanupCallback&& aCleanupCallback,
|
||||
ErrorResult& aRv);
|
||||
nsIGlobalObject* aGlobal, dom::Function* aCallback,
|
||||
CleanupCallback&& aCleanupCallback, ErrorResult& aRv);
|
||||
|
||||
static bool IsPromise(JSContext* aCx, JS::Handle<JS::Value> aValue) {
|
||||
if (!aValue.isObject()) {
|
||||
|
@ -68,8 +67,6 @@ class ExtensionEventListener final : public mozIExtensionEventListener {
|
|||
return global;
|
||||
}
|
||||
|
||||
ExtensionBrowser* GetExtensionBrowser() const { return mExtensionBrowser; }
|
||||
|
||||
void Cleanup() {
|
||||
if (mWorkerRef) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
@ -80,21 +77,13 @@ class ExtensionEventListener final : public mozIExtensionEventListener {
|
|||
|
||||
mGlobal = nullptr;
|
||||
mCallback = nullptr;
|
||||
mExtensionBrowser = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
ExtensionEventListener(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser,
|
||||
dom::Function* aCallback)
|
||||
ExtensionEventListener(nsIGlobalObject* aGlobal, dom::Function* aCallback)
|
||||
: mGlobal(do_GetWeakReference(aGlobal)),
|
||||
mExtensionBrowser(aExtensionBrowser),
|
||||
mCallback(aCallback),
|
||||
mMutex("ExtensionEventListener::mMutex") {
|
||||
MOZ_ASSERT(aGlobal);
|
||||
MOZ_ASSERT(aExtensionBrowser);
|
||||
MOZ_ASSERT(aCallback);
|
||||
};
|
||||
mMutex("ExtensionEventListener::mMutex"){};
|
||||
|
||||
static UniquePtr<dom::StructuredCloneHolder> SerializeCallArguments(
|
||||
const nsTArray<JS::Value>& aArgs, JSContext* aCx, ErrorResult& aRv);
|
||||
|
@ -106,7 +95,6 @@ class ExtensionEventListener final : public mozIExtensionEventListener {
|
|||
|
||||
// Accessed only on the owning thread.
|
||||
nsWeakPtr mGlobal;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
RefPtr<dom::Function> mCallback;
|
||||
|
||||
// Used to make sure we are not going to release the
|
||||
|
@ -143,7 +131,6 @@ class ExtensionListenerCallWorkerRunnable : public dom::WorkerRunnable {
|
|||
|
||||
if (aCallOptions) {
|
||||
aCallOptions->GetApiObjectType(&mAPIObjectType);
|
||||
aCallOptions->GetApiObjectPrepended(&mAPIObjectPrepended);
|
||||
aCallOptions->GetCallbackType(&mCallbackArgType);
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +166,6 @@ class ExtensionListenerCallWorkerRunnable : public dom::WorkerRunnable {
|
|||
RefPtr<dom::Promise> mPromiseResult;
|
||||
bool mIsCallResultCancelled = false;
|
||||
// Call Options.
|
||||
bool mAPIObjectPrepended;
|
||||
APIObjectType mAPIObjectType;
|
||||
CallbackType mCallbackArgType;
|
||||
};
|
||||
|
|
|
@ -19,13 +19,11 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionEventManager)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ExtensionEventManager)
|
||||
tmp->mListeners.clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExtensionBrowser)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ExtensionEventManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExtensionBrowser)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ExtensionEventManager)
|
||||
|
@ -40,18 +38,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionEventManager)
|
|||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ExtensionEventManager::ExtensionEventManager(
|
||||
nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser,
|
||||
const nsAString& aNamespace, const nsAString& aEventName,
|
||||
const nsAString& aObjectType, const nsAString& aObjectId)
|
||||
ExtensionEventManager::ExtensionEventManager(nsIGlobalObject* aGlobal,
|
||||
const nsAString& aNamespace,
|
||||
const nsAString& aEventName,
|
||||
const nsAString& aObjectType,
|
||||
const nsAString& aObjectId)
|
||||
: mGlobal(aGlobal),
|
||||
mExtensionBrowser(aExtensionBrowser),
|
||||
mAPINamespace(aNamespace),
|
||||
mEventName(aEventName),
|
||||
mAPIObjectType(aObjectType),
|
||||
mAPIObjectId(aObjectId) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mExtensionBrowser);
|
||||
|
||||
RefPtr<ExtensionEventManager> self = this;
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
@ -96,7 +93,7 @@ void ExtensionEventManager::AddListener(
|
|||
|
||||
IgnoredErrorResult rv;
|
||||
RefPtr<ExtensionEventListener> wrappedCb = ExtensionEventListener::Create(
|
||||
mGlobal, mExtensionBrowser, &aCallback,
|
||||
mGlobal, &aCallback,
|
||||
[self = std::move(self)]() { self->ReleaseListeners(); }, rv);
|
||||
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
|
|
|
@ -38,7 +38,6 @@ class ExtensionEventManager final : public nsISupports,
|
|||
public nsWrapperCache,
|
||||
public ExtensionAPIBase {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
nsString mAPINamespace;
|
||||
nsString mEventName;
|
||||
nsString mAPIObjectType;
|
||||
|
@ -58,9 +57,6 @@ class ExtensionEventManager final : public nsISupports,
|
|||
protected:
|
||||
// ExtensionAPIBase methods
|
||||
nsIGlobalObject* GetGlobalObject() const override { return mGlobal; }
|
||||
ExtensionBrowser* GetExtensionBrowser() const override {
|
||||
return mExtensionBrowser;
|
||||
}
|
||||
|
||||
nsString GetAPINamespace() const override { return mAPINamespace; }
|
||||
|
||||
|
@ -69,9 +65,7 @@ class ExtensionEventManager final : public nsISupports,
|
|||
nsString GetAPIObjectId() const override { return mAPIObjectId; }
|
||||
|
||||
public:
|
||||
ExtensionEventManager(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser,
|
||||
const nsAString& aNamespace,
|
||||
ExtensionEventManager(nsIGlobalObject* aGlobal, const nsAString& aNamespace,
|
||||
const nsAString& aEventName,
|
||||
const nsAString& aObjectType = VoidString(),
|
||||
const nsAString& aObjectId = VoidString());
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace extensions {
|
|||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionMockAPI);
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionMockAPI)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ExtensionMockAPI, mGlobal,
|
||||
mExtensionBrowser, mOnTestEventMgr);
|
||||
mOnTestEventMgr);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionMockAPI)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
|
@ -25,9 +25,8 @@ NS_INTERFACE_MAP_END
|
|||
|
||||
ExtensionMockAPI::ExtensionMockAPI(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser)
|
||||
: mGlobal(aGlobal), mExtensionBrowser(aExtensionBrowser) {
|
||||
: mGlobal(aGlobal) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mExtensionBrowser);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -44,12 +43,40 @@ nsIGlobalObject* ExtensionMockAPI::GetParentObject() const { return mGlobal; }
|
|||
|
||||
void ExtensionMockAPI::GetPropertyAsErrorObject(
|
||||
JSContext* aCx, JS::MutableHandle<JS::Value> aRetval) {
|
||||
ExtensionAPIBase::GetWebExtPropertyAsJSValue(aCx, u"propertyAsErrorObject"_ns,
|
||||
aRetval);
|
||||
IgnoredErrorResult rv;
|
||||
RefPtr<ExtensionAPIGetProperty> request =
|
||||
GetProperty(u"propertyAsErrorObject"_ns);
|
||||
request->Run(mGlobal, aCx, aRetval, rv);
|
||||
if (rv.Failed()) {
|
||||
NS_WARNING("ExtensionMockAPI::GetPropertyAsErrorObject failure");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionMockAPI::GetPropertyAsString(DOMString& aRetval) {
|
||||
GetWebExtPropertyAsString(u"getPropertyAsString"_ns, aRetval);
|
||||
IgnoredErrorResult rv;
|
||||
|
||||
dom::AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(GetParentObject())) {
|
||||
NS_WARNING("ExtensionMockAPI::GetPropertyAsId fail to init jsapi");
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::RootedValue retval(cx);
|
||||
|
||||
RefPtr<ExtensionAPIGetProperty> request =
|
||||
GetProperty(u"getPropertyAsString"_ns);
|
||||
request->Run(mGlobal, cx, &retval, rv);
|
||||
if (rv.Failed()) {
|
||||
NS_WARNING("ExtensionMockAPI::GetPropertyAsString failure");
|
||||
return;
|
||||
}
|
||||
nsAutoJSString strRetval;
|
||||
if (!retval.isString() || !strRetval.init(cx, retval)) {
|
||||
NS_WARNING("ExtensionMockAPI::GetPropertyAsString got a non string result");
|
||||
return;
|
||||
}
|
||||
aRetval.SetKnownLiveString(strRetval);
|
||||
}
|
||||
|
||||
ExtensionEventManager* ExtensionMockAPI::OnTestEvent() {
|
||||
|
@ -60,5 +87,27 @@ ExtensionEventManager* ExtensionMockAPI::OnTestEvent() {
|
|||
return mOnTestEventMgr;
|
||||
}
|
||||
|
||||
already_AddRefed<ExtensionPort> ExtensionMockAPI::CallWebExtMethodReturnsPort(
|
||||
JSContext* aCx, const nsAString& aApiMethod,
|
||||
const dom::Sequence<JS::Value>& aArgs, ErrorResult& aRv) {
|
||||
JS::Rooted<JS::Value> apiResult(aCx);
|
||||
auto request = CallSyncFunction(u"methodReturnsPort"_ns);
|
||||
request->Run(mGlobal, aCx, aArgs, &apiResult, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IgnoredErrorResult rv;
|
||||
RefPtr<ExtensionPort> port = ExtensionPort::Create(mGlobal, apiResult, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
// ExtensionPort::Create doesn't throw the js exception with the generic
|
||||
// error message as the "api request forwarding" helper classes.
|
||||
ThrowUnexpectedError(aCx, aRv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return port.forget();
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -33,7 +33,6 @@ class ExtensionMockAPI final : public nsISupports,
|
|||
public nsWrapperCache,
|
||||
public ExtensionAPINamespace {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
RefPtr<ExtensionEventManager> mOnTestEventMgr;
|
||||
|
||||
~ExtensionMockAPI() = default;
|
||||
|
@ -42,10 +41,6 @@ class ExtensionMockAPI final : public nsISupports,
|
|||
// ExtensionAPIBase methods
|
||||
nsIGlobalObject* GetGlobalObject() const override { return mGlobal; }
|
||||
|
||||
ExtensionBrowser* GetExtensionBrowser() const override {
|
||||
return mExtensionBrowser;
|
||||
}
|
||||
|
||||
nsString GetAPINamespace() const override { return u"mockExtensionAPI"_ns; }
|
||||
|
||||
public:
|
||||
|
@ -65,6 +60,10 @@ class ExtensionMockAPI final : public nsISupports,
|
|||
JS::MutableHandle<JS::Value> aRetval);
|
||||
void GetPropertyAsString(DOMString& aRetval);
|
||||
|
||||
already_AddRefed<ExtensionPort> CallWebExtMethodReturnsPort(
|
||||
JSContext* aCx, const nsAString& aApiMethod,
|
||||
const dom::Sequence<JS::Value>& aArgs, ErrorResult& aRv);
|
||||
|
||||
ExtensionEventManager* OnTestEvent();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
|
|
@ -16,25 +16,9 @@ namespace extensions {
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionPort);
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionPort)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(ExtensionPort)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ExtensionPort)
|
||||
// Clean the entry for this instance from the ports lookup map
|
||||
// stored in the related ExtensionBrowser instance.
|
||||
tmp->ForgetReleasedPort();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExtensionBrowser, mOnDisconnectEventMgr,
|
||||
mOnMessageEventMgr)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ExtensionPort)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExtensionBrowser, mOnDisconnectEventMgr,
|
||||
mOnMessageEventMgr)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(ExtensionPort)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ExtensionPort, mGlobal,
|
||||
mOnDisconnectEventMgr,
|
||||
mOnMessageEventMgr);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionPort)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
|
@ -43,16 +27,8 @@ NS_INTERFACE_MAP_END
|
|||
|
||||
// static
|
||||
already_AddRefed<ExtensionPort> ExtensionPort::Create(
|
||||
nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser,
|
||||
UniquePtr<dom::ExtensionPortDescriptor>&& aPortDescriptor) {
|
||||
RefPtr<ExtensionPort> port =
|
||||
new ExtensionPort(aGlobal, aExtensionBrowser, std::move(aPortDescriptor));
|
||||
return port.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
UniquePtr<dom::ExtensionPortDescriptor> ExtensionPort::ToPortDescriptor(
|
||||
JS::Handle<JS::Value> aDescriptorValue, ErrorResult& aRv) {
|
||||
nsIGlobalObject* aGlobal, JS::Handle<JS::Value> aDescriptorValue,
|
||||
ErrorResult& aRv) {
|
||||
if (!aDescriptorValue.isObject()) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
|
@ -66,26 +42,16 @@ UniquePtr<dom::ExtensionPortDescriptor> ExtensionPort::ToPortDescriptor(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return portDescriptor;
|
||||
RefPtr<ExtensionPort> port =
|
||||
new ExtensionPort(aGlobal, std::move(portDescriptor));
|
||||
return port.forget();
|
||||
}
|
||||
|
||||
ExtensionPort::ExtensionPort(
|
||||
nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser,
|
||||
UniquePtr<dom::ExtensionPortDescriptor>&& aPortDescriptor)
|
||||
: mGlobal(aGlobal),
|
||||
mExtensionBrowser(aExtensionBrowser),
|
||||
mPortDescriptor(std::move(aPortDescriptor)) {
|
||||
nsIGlobalObject* aGlobal,
|
||||
UniquePtr<dom::ExtensionPortDescriptor> aPortDescriptor)
|
||||
: mGlobal(aGlobal), mPortDescriptor(std::move(aPortDescriptor)) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mExtensionBrowser);
|
||||
}
|
||||
|
||||
void ExtensionPort::ForgetReleasedPort() {
|
||||
if (mExtensionBrowser) {
|
||||
mExtensionBrowser->ForgetReleasedPort(mPortDescriptor->mPortId);
|
||||
mExtensionBrowser = nullptr;
|
||||
}
|
||||
mPortDescriptor = nullptr;
|
||||
mGlobal = nullptr;
|
||||
}
|
||||
|
||||
nsString ExtensionPort::GetAPIObjectId() const {
|
||||
|
|
|
@ -29,29 +29,20 @@ class ExtensionEventManager;
|
|||
|
||||
class ExtensionPort final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public SupportsWeakPtr,
|
||||
public ExtensionAPIBase {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
RefPtr<ExtensionEventManager> mOnDisconnectEventMgr;
|
||||
RefPtr<ExtensionEventManager> mOnMessageEventMgr;
|
||||
UniquePtr<dom::ExtensionPortDescriptor> mPortDescriptor;
|
||||
RefPtr<dom::Function> mCallback;
|
||||
|
||||
~ExtensionPort() = default;
|
||||
ExtensionPort(nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser,
|
||||
UniquePtr<dom::ExtensionPortDescriptor>&& aPortDescriptor);
|
||||
|
||||
void ForgetReleasedPort();
|
||||
ExtensionPort(nsIGlobalObject* aGlobal,
|
||||
UniquePtr<dom::ExtensionPortDescriptor> aPortDescriptor);
|
||||
|
||||
protected:
|
||||
// ExtensionAPIBase methods
|
||||
nsIGlobalObject* GetGlobalObject() const override { return mGlobal; }
|
||||
|
||||
ExtensionBrowser* GetExtensionBrowser() const override {
|
||||
return mExtensionBrowser;
|
||||
}
|
||||
|
||||
nsString GetAPINamespace() const override { return u"runtime"_ns; }
|
||||
|
||||
nsString GetAPIObjectType() const override { return u"Port"_ns; }
|
||||
|
@ -60,11 +51,8 @@ class ExtensionPort final : public nsISupports,
|
|||
|
||||
public:
|
||||
static already_AddRefed<ExtensionPort> Create(
|
||||
nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser,
|
||||
UniquePtr<dom::ExtensionPortDescriptor>&& aPortDescriptor);
|
||||
|
||||
static UniquePtr<dom::ExtensionPortDescriptor> ToPortDescriptor(
|
||||
JS::Handle<JS::Value> aDescriptorValue, ErrorResult& aRv);
|
||||
nsIGlobalObject* aGlobal, JS::Handle<JS::Value> aDescriptorValue,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// nsWrapperCache interface methods
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
|
@ -76,11 +64,17 @@ class ExtensionPort final : public nsISupports,
|
|||
ExtensionEventManager* OnMessage();
|
||||
|
||||
void GetName(nsAString& aString);
|
||||
void GetError(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval) {
|
||||
GetWebExtPropertyAsJSValue(aCx, u"error"_ns, aRetval);
|
||||
void GetError(JSContext* aCx, JS::MutableHandle<JSObject*> aResult) {
|
||||
// TODO: this is currently just a placeholder, should be filled in
|
||||
// with the actual implementation (which may send to the API request
|
||||
// handler an API request to get the property value from the port object
|
||||
// representation that lives on the main thread).
|
||||
}
|
||||
void GetSender(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval) {
|
||||
GetWebExtPropertyAsJSValue(aCx, u"sender"_ns, aRetval);
|
||||
void GetSender(JSContext* aCx, JS::MutableHandle<JSObject*> aResult) {
|
||||
// TODO: this is currently just a placeholder, needed to please the
|
||||
// webidl binding which excepts this property to always return
|
||||
// an object.
|
||||
aResult.set(JS_NewPlainObject(aCx));
|
||||
};
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
|
||||
#include "ExtensionRuntime.h"
|
||||
#include "ExtensionEventManager.h"
|
||||
|
||||
#include "mozilla/dom/ExtensionRuntimeBinding.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace extensions {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionRuntime);
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionRuntime)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(
|
||||
ExtensionRuntime, mGlobal, mExtensionBrowser, mOnStartupEventMgr,
|
||||
mOnInstalledEventMgr, mOnUpdateAvailableEventMgr, mOnConnectEventMgr,
|
||||
mOnConnectExternalEventMgr, mOnMessageEventMgr, mOnMessageExternalEventMgr);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionRuntime)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ExtensionRuntime::ExtensionRuntime(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser)
|
||||
: mGlobal(aGlobal), mExtensionBrowser(aExtensionBrowser) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mExtensionBrowser);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool ExtensionRuntime::IsAllowed(JSContext* aCx, JSObject* aGlobal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject* ExtensionRuntime::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return dom::ExtensionRuntime_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsIGlobalObject* ExtensionRuntime::GetParentObject() const { return mGlobal; }
|
||||
|
||||
void ExtensionRuntime::GetLastError(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aRetval) {
|
||||
mExtensionBrowser->GetLastError(aRetval);
|
||||
}
|
||||
|
||||
void ExtensionRuntime::GetId(DOMString& aRetval) {
|
||||
GetWebExtPropertyAsString(u"id"_ns, aRetval);
|
||||
}
|
||||
|
||||
ExtensionEventManager* ExtensionRuntime::OnStartup() {
|
||||
if (!mOnStartupEventMgr) {
|
||||
mOnStartupEventMgr = CreateEventManager(u"onStartup"_ns);
|
||||
}
|
||||
|
||||
return mOnStartupEventMgr;
|
||||
}
|
||||
|
||||
ExtensionEventManager* ExtensionRuntime::OnInstalled() {
|
||||
if (!mOnInstalledEventMgr) {
|
||||
mOnInstalledEventMgr = CreateEventManager(u"onInstalled"_ns);
|
||||
}
|
||||
|
||||
return mOnInstalledEventMgr;
|
||||
}
|
||||
|
||||
ExtensionEventManager* ExtensionRuntime::OnUpdateAvailable() {
|
||||
if (!mOnUpdateAvailableEventMgr) {
|
||||
mOnUpdateAvailableEventMgr = CreateEventManager(u"onUpdateAvailable"_ns);
|
||||
}
|
||||
|
||||
return mOnUpdateAvailableEventMgr;
|
||||
}
|
||||
|
||||
ExtensionEventManager* ExtensionRuntime::OnConnect() {
|
||||
if (!mOnConnectEventMgr) {
|
||||
mOnConnectEventMgr = CreateEventManager(u"onConnect"_ns);
|
||||
}
|
||||
|
||||
return mOnConnectEventMgr;
|
||||
}
|
||||
|
||||
ExtensionEventManager* ExtensionRuntime::OnConnectExternal() {
|
||||
if (!mOnConnectExternalEventMgr) {
|
||||
mOnConnectExternalEventMgr = CreateEventManager(u"onConnectExternal"_ns);
|
||||
}
|
||||
|
||||
return mOnConnectExternalEventMgr;
|
||||
}
|
||||
|
||||
ExtensionEventManager* ExtensionRuntime::OnMessage() {
|
||||
if (!mOnMessageEventMgr) {
|
||||
mOnMessageEventMgr = CreateEventManager(u"onMessage"_ns);
|
||||
}
|
||||
|
||||
return mOnMessageEventMgr;
|
||||
}
|
||||
|
||||
ExtensionEventManager* ExtensionRuntime::OnMessageExternal() {
|
||||
if (!mOnMessageExternalEventMgr) {
|
||||
mOnMessageExternalEventMgr = CreateEventManager(u"onMessageExternal"_ns);
|
||||
}
|
||||
|
||||
return mOnMessageExternalEventMgr;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
|
@ -1,84 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
|
||||
#ifndef mozilla_extensions_ExtensionRuntime_h
|
||||
#define mozilla_extensions_ExtensionRuntime_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "ExtensionAPIBase.h"
|
||||
#include "ExtensionBrowser.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class ExtensionEventManager;
|
||||
|
||||
class ExtensionRuntime final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public ExtensionAPINamespace {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
RefPtr<ExtensionEventManager> mOnStartupEventMgr;
|
||||
RefPtr<ExtensionEventManager> mOnInstalledEventMgr;
|
||||
RefPtr<ExtensionEventManager> mOnUpdateAvailableEventMgr;
|
||||
RefPtr<ExtensionEventManager> mOnConnectEventMgr;
|
||||
RefPtr<ExtensionEventManager> mOnConnectExternalEventMgr;
|
||||
RefPtr<ExtensionEventManager> mOnMessageEventMgr;
|
||||
RefPtr<ExtensionEventManager> mOnMessageExternalEventMgr;
|
||||
|
||||
~ExtensionRuntime() = default;
|
||||
|
||||
public:
|
||||
ExtensionRuntime(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser);
|
||||
|
||||
// ExtensionAPIBase methods
|
||||
nsIGlobalObject* GetGlobalObject() const override { return mGlobal; }
|
||||
|
||||
ExtensionBrowser* GetExtensionBrowser() const override {
|
||||
return mExtensionBrowser;
|
||||
}
|
||||
|
||||
nsString GetAPINamespace() const override { return u"runtime"_ns; }
|
||||
|
||||
// nsWrapperCache interface methods
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// DOM bindings methods
|
||||
static bool IsAllowed(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
nsIGlobalObject* GetParentObject() const;
|
||||
|
||||
ExtensionEventManager* OnStartup();
|
||||
ExtensionEventManager* OnInstalled();
|
||||
ExtensionEventManager* OnUpdateAvailable();
|
||||
ExtensionEventManager* OnConnect();
|
||||
ExtensionEventManager* OnConnectExternal();
|
||||
ExtensionEventManager* OnMessage();
|
||||
ExtensionEventManager* OnMessageExternal();
|
||||
|
||||
void GetLastError(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
|
||||
void GetId(DOMString& aRetval);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionRuntime)
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_extensions_ExtensionRuntime_h
|
|
@ -1,64 +0,0 @@
|
|||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
|
||||
#include "ExtensionTest.h"
|
||||
#include "ExtensionEventManager.h"
|
||||
|
||||
#include "mozilla/dom/ExtensionTestBinding.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace extensions {
|
||||
|
||||
bool IsInAutomation(JSContext* aCx, JSObject* aGlobal) {
|
||||
return NS_IsMainThread()
|
||||
? xpc::IsInAutomation()
|
||||
: dom::WorkerGlobalScope::IsInAutomation(aCx, aGlobal);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionTest);
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionTest)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ExtensionTest, mGlobal, mExtensionBrowser,
|
||||
mOnMessageEventMgr);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionTest)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ExtensionTest::ExtensionTest(nsIGlobalObject* aGlobal,
|
||||
ExtensionBrowser* aExtensionBrowser)
|
||||
: mGlobal(aGlobal), mExtensionBrowser(aExtensionBrowser) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mExtensionBrowser);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool ExtensionTest::IsAllowed(JSContext* aCx, JSObject* aGlobal) {
|
||||
// Allow browser.test API namespace while running in xpcshell tests.
|
||||
if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return IsInAutomation(aCx, aGlobal);
|
||||
}
|
||||
|
||||
JSObject* ExtensionTest::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return dom::ExtensionTest_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsIGlobalObject* ExtensionTest::GetParentObject() const { return mGlobal; }
|
||||
|
||||
ExtensionEventManager* ExtensionTest::OnMessage() {
|
||||
if (!mOnMessageEventMgr) {
|
||||
mOnMessageEventMgr = CreateEventManager(u"onMessage"_ns);
|
||||
}
|
||||
|
||||
return mOnMessageEventMgr;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
|
@ -1,70 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
|
||||
#ifndef mozilla_extensions_ExtensionTest_h
|
||||
#define mozilla_extensions_ExtensionTest_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "ExtensionAPIBase.h"
|
||||
#include "ExtensionBrowser.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class ExtensionEventManager;
|
||||
|
||||
bool IsInAutomation(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
class ExtensionTest final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public ExtensionAPINamespace {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<ExtensionBrowser> mExtensionBrowser;
|
||||
RefPtr<ExtensionEventManager> mOnMessageEventMgr;
|
||||
|
||||
~ExtensionTest() = default;
|
||||
|
||||
public:
|
||||
ExtensionTest(nsIGlobalObject* aGlobal, ExtensionBrowser* aExtensionBrowser);
|
||||
|
||||
// ExtensionAPIBase methods
|
||||
nsIGlobalObject* GetGlobalObject() const override { return mGlobal; }
|
||||
|
||||
ExtensionBrowser* GetExtensionBrowser() const override {
|
||||
return mExtensionBrowser;
|
||||
}
|
||||
|
||||
nsString GetAPINamespace() const override { return u"test"_ns; }
|
||||
|
||||
// nsWrapperCache interface methods
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// DOM bindings methods
|
||||
static bool IsAllowed(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
nsIGlobalObject* GetParentObject() const;
|
||||
|
||||
ExtensionEventManager* OnMessage();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionTest)
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_extensions_ExtensionTest_h
|
|
@ -1,78 +0,0 @@
|
|||
# -*- Mode:Python; tab-width:8; indent-tabs-mode:nil -*- */
|
||||
# vim: set ts=8 sts=4 et sw=4 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/.
|
||||
|
||||
# WebExtension WebIDL API Bindings Configuration, used by the script
|
||||
# `dom/extensions-webidl/GenerateWebIDLBindingsFromJSONSchema.py`
|
||||
# to customize the WebIDL generated based on the WebExtensions API JSON Schemas.
|
||||
#
|
||||
# Generating the WebIDL definitions for some of the WebExtensions API does require
|
||||
# some special handling, there are corresponding entries in the configuration tables
|
||||
# below.
|
||||
#
|
||||
|
||||
# Mapping table between the JSON Schema types (represented as keys of the map)
|
||||
# and the related WebIDL type (represented by the value in the map).
|
||||
# Any mapping missing from this table will fallback to use the "any" webidl type
|
||||
# (See GenerateWebIDLBindings.py WebIDLHelpers.webidl_type_from_mapping method).
|
||||
#
|
||||
# NOTE: Please keep this table in alphabetic order (upper and lower case in two
|
||||
# separate alphabetic orders, group of the upcase ones first).
|
||||
WEBEXT_TYPES_MAPPING = {
|
||||
"ExpectedError": "any", # Only used in test.assertThrows/assertRejects
|
||||
"Port": "ExtensionPort",
|
||||
"Promise": "Promise<any>",
|
||||
"StreamFilter": "ExtensionStreamFilter",
|
||||
"any": "any",
|
||||
"boolean": "boolean",
|
||||
"number": "float",
|
||||
"function": "Function",
|
||||
"integer": "long",
|
||||
"object": "any", # TODO: as a follow up we may look into generating webidl dictionaries to achieve a more precise mapping
|
||||
"runtime.Port": "ExtensionPort",
|
||||
"string": "DOMString",
|
||||
"types.Setting": "ExtensionSetting",
|
||||
}
|
||||
|
||||
# Mapping table for some APIs that do require special handling and a
|
||||
# specific stub method should be set in the generated webidl extended
|
||||
# attribute `WebExtensionStub`.
|
||||
#
|
||||
# The key in this map represent the API method name (including the
|
||||
# API namespace that is part of), the value is the value to set on the
|
||||
# `WebExtensionStub` webidl extended attribute:
|
||||
#
|
||||
# "namespace.methodName": "WebExtensionStubName",
|
||||
#
|
||||
# NOTE: Please keep this table in alphabetic order.
|
||||
WEBEXT_STUBS_MAPPING = {
|
||||
"runtime.connect": "ReturnsPort",
|
||||
"runtime.connectNative": "ReturnsPort",
|
||||
"runtime.getURL": "ReturnsString",
|
||||
"test.assertEq": "NotImplementedNoReturn",
|
||||
"test.assertRejects": "NotImplementedAsync",
|
||||
"test.assertThrows": "NotImplementedNoReturn",
|
||||
"test.withHandlingUserInput": "NotImplementedNoReturn",
|
||||
}
|
||||
|
||||
# Mapping table for the directories where the JSON API schema will be loaded
|
||||
# from.
|
||||
WEBEXT_SCHEMADIRS_MAPPING = {
|
||||
"toolkit": ["toolkit", "components", "extensions", "schemas"],
|
||||
"browser": ["browser", "components", "extensions", "schemas"],
|
||||
"mobile": ["mobile", "android", "components", "extensions", "schemas"],
|
||||
}
|
||||
|
||||
# List of toolkit-level WebExtensions API namespaces that are not included
|
||||
# in android builds.
|
||||
#
|
||||
# NOTE: keep this list in sync with the API namespaces excluded in
|
||||
# - toolkit/components/extensions/jar.mn
|
||||
# - toolkit/components/extensions/schemas/jar.mn
|
||||
WEBEXT_ANDROID_EXCLUDED = [
|
||||
"captivePortal",
|
||||
"geckoProfiler",
|
||||
"identity"
|
||||
]
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,145 +0,0 @@
|
|||
# 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/.
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Sanity check (ensure the script has been executed through `mach python`).
|
||||
try:
|
||||
import buildconfig
|
||||
|
||||
# try to access an existing property to please flake8 linting and as an
|
||||
# additional sanity check.
|
||||
buildconfig.topsrcdir
|
||||
except ModuleNotFoundError or AttributeError:
|
||||
print(
|
||||
"This script should be executed using `mach python %s`" % __file__,
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
# Add the current directory to the module path (needed to be able to load
|
||||
# GenerateWebIDLBindings without having to make it recognized as a python package).
|
||||
module_dir = os.path.dirname(__file__)
|
||||
sys.path.append(module_dir)
|
||||
|
||||
from GenerateWebIDLBindings import (
|
||||
load_and_parse_JSONSchema,
|
||||
set_logging_level,
|
||||
APIEntry,
|
||||
)
|
||||
|
||||
|
||||
def get_args_and_argparser():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
# global cli flags shared by all sub-commands.
|
||||
parser.add_argument("--verbose", "-v", action="count", default=0)
|
||||
parser.add_argument(
|
||||
"--diff-command",
|
||||
type=str,
|
||||
metavar="DIFFCMD",
|
||||
help="select the diff command used to generate diffs (defaults to 'diff')",
|
||||
)
|
||||
|
||||
# --dump-namespaces-list flag (this is also the default for the 'inspect' command
|
||||
# when no other flag is specified).
|
||||
parser.add_argument(
|
||||
"--dump-namespaces-list",
|
||||
action="store_true",
|
||||
help="'inspect' command flag - dump list of all API namespaces defined in all"
|
||||
+ " JSONSchema files loaded",
|
||||
)
|
||||
|
||||
# --dump-platform-diffs flag and other sub-flags that can be used with it.
|
||||
parser.add_argument(
|
||||
"--dump-platform-diffs",
|
||||
action="store_true",
|
||||
help="'inspect' command flag - list all APIs with platform specific differences",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--only-if-webidl-diffs",
|
||||
action="store_true",
|
||||
help="'inspect' command flag - limits --dump-platform-diff to APIs with differences"
|
||||
+ " in the generated webidl",
|
||||
)
|
||||
|
||||
# --dump-namespaces-info flag and other flags that can be used with it.
|
||||
parser.add_argument(
|
||||
"--dump-namespaces-info",
|
||||
nargs="+",
|
||||
type=str,
|
||||
metavar="NAMESPACE",
|
||||
help="'inspect' command flag - dump data loaded for the given NAMESPACE(s)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--only-in-schema-group",
|
||||
type=str,
|
||||
metavar="SCHEMAGROUP",
|
||||
help="'inspect' command flag - list api namespace in the given schema group"
|
||||
+ " (toolkit, browser or mobile)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return [args, parser]
|
||||
|
||||
|
||||
# Run the 'inspect' subcommand: these command (and its cli flags) is useful to
|
||||
# inspect the JSONSchema data loaded, which is explicitly useful when debugging
|
||||
# or evaluating changes to this scripts (e.g. changes that may be needed if the
|
||||
# API namespace definition isn't complete or its generated content has issues).
|
||||
def run_inspect_command(args, schemas, parser):
|
||||
# --dump-namespaces-info: print a summary view of all the namespaces available
|
||||
# after loading and parsing all the collected JSON schema files.
|
||||
if args.dump_namespaces_info:
|
||||
if "ALL" in args.dump_namespaces_info:
|
||||
for namespace in schemas.get_all_namespace_names():
|
||||
schemas.get_namespace(namespace).dump(args.only_in_schema_group)
|
||||
|
||||
return
|
||||
|
||||
for namespace in args.dump_namespaces_info:
|
||||
schemas.get_namespace(namespace).dump(args.only_in_schema_group)
|
||||
return
|
||||
|
||||
# --dump-platform-diffs: print diffs for the JSON schema where we detected
|
||||
# differences between the desktop and mobile JSON schema files.
|
||||
if args.dump_platform_diffs:
|
||||
for entry in APIEntry.in_multiple_groups:
|
||||
entry.dump_platform_diff(args.diff_command, args.only_if_webidl_diffs)
|
||||
return
|
||||
|
||||
# Dump the list of all known API namespaces based on all the loaded JSONSchema data.
|
||||
if args.dump_namespaces_list:
|
||||
schemas.dump_namespaces()
|
||||
return
|
||||
|
||||
# Print the help message and exit 1 as a fallback.
|
||||
print(
|
||||
"ERROR: No option selected, choose one from the following usage message.\n",
|
||||
file=sys.stderr,
|
||||
)
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
"""Entry point function for this script"""
|
||||
|
||||
[args, parser] = get_args_and_argparser()
|
||||
set_logging_level(args.verbose)
|
||||
schemas = load_and_parse_JSONSchema()
|
||||
run_inspect_command(args, schemas, parser)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
else:
|
||||
print(
|
||||
"%s is only meant to be loaded as a script using `mach python %s`"
|
||||
% (__file__, __file__)
|
||||
)
|
||||
sys.exit(1)
|
|
@ -7,7 +7,6 @@
|
|||
with Files("**"):
|
||||
BUG_COMPONENT = ("WebExtensions", "General")
|
||||
|
||||
# WebExtensions API objects and request handling internals.
|
||||
UNIFIED_SOURCES += [
|
||||
"ExtensionAPIBase.cpp",
|
||||
"ExtensionAPIRequest.cpp",
|
||||
|
@ -25,19 +24,6 @@ EXPORTS.mozilla.extensions += [
|
|||
"ExtensionPort.h",
|
||||
]
|
||||
|
||||
# WebExtensions API namespaces.
|
||||
UNIFIED_SOURCES += [
|
||||
"ExtensionAlarms.cpp",
|
||||
"ExtensionRuntime.cpp",
|
||||
"ExtensionTest.cpp",
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.extensions += [
|
||||
"ExtensionAlarms.h",
|
||||
"ExtensionRuntime.h",
|
||||
"ExtensionTest.h",
|
||||
]
|
||||
|
||||
# The following is not a real WebExtensions API, it is a test WebIDL
|
||||
# interface that includes a collection of the cases useful to unit
|
||||
# test the API request forwarding mechanism without tying it to
|
||||
|
|
|
@ -39,22 +39,12 @@ let JSPROCESSACTORS = {
|
|||
moduleURI: "resource://gre/modules/ContentPrefServiceChild.jsm",
|
||||
},
|
||||
},
|
||||
|
||||
ExtensionContent: {
|
||||
child: {
|
||||
moduleURI: "resource://gre/modules/ExtensionContent.jsm",
|
||||
},
|
||||
includeParent: true,
|
||||
},
|
||||
|
||||
ProcessConduits: {
|
||||
parent: {
|
||||
moduleURI: "resource://gre/modules/ConduitsParent.jsm",
|
||||
},
|
||||
child: {
|
||||
moduleURI: "resource://gre/modules/ConduitsChild.jsm",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче