diff --git a/dom/base/SerializedStackHolder.cpp b/dom/base/SerializedStackHolder.cpp index 76352832a622..fa52de9ba2cf 100644 --- a/dom/base/SerializedStackHolder.cpp +++ b/dom/base/SerializedStackHolder.cpp @@ -91,10 +91,6 @@ UniquePtr GetCurrentStackForNetMonitor(JSContext* aCx) { MOZ_ASSERT_IF(!NS_IsMainThread(), GetCurrentThreadWorkerPrivate()->IsWatchedByDevTools()); - return GetCurrentStack(aCx); -} - -UniquePtr GetCurrentStack(JSContext* aCx) { UniquePtr stack = MakeUnique(); stack->SerializeCurrentStack(aCx); return stack; diff --git a/dom/base/SerializedStackHolder.h b/dom/base/SerializedStackHolder.h index ec8d652f0224..377f9c4f8247 100644 --- a/dom/base/SerializedStackHolder.h +++ b/dom/base/SerializedStackHolder.h @@ -55,9 +55,6 @@ class SerializedStackHolder { // be checked before creating the stack. UniquePtr GetCurrentStackForNetMonitor(JSContext* aCx); -// Construct a stack for the current thread. -UniquePtr GetCurrentStack(JSContext* aCx); - // If aStackHolder is non-null, this notifies the net monitor that aStackHolder // is the stack from which aChannel originates. This must be called on the main // thread. This call is synchronous, and aChannel and aStackHolder will not be diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index e243ad6227f8..4f456dfc6175 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1570,28 +1570,6 @@ DOMInterfaces = { 'nativeType': 'nsXULElement', }, -# WebExtension API - -'ExtensionBrowser': { - 'headerFile': 'mozilla/extensions/ExtensionBrowser.h', - 'nativeType': 'mozilla::extensions::ExtensionBrowser', -}, - -'ExtensionMockAPI': { - 'headerFile': 'mozilla/extensions/ExtensionMockAPI.h', - 'nativeType': 'mozilla::extensions::ExtensionMockAPI', -}, - -'ExtensionEventManager': { - 'headerFile': 'mozilla/extensions/ExtensionEventManager.h', - 'nativeType': 'mozilla::extensions::ExtensionEventManager', -}, - -'ExtensionPort': { - 'headerFile': 'mozilla/extensions/ExtensionPort.h', - 'nativeType': 'mozilla::extensions::ExtensionPort', -}, - #################################### # Test Interfaces of various sorts # #################################### diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 34745d36018a..298bf7d261cd 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -9485,22 +9485,12 @@ class CGPerSignatureCall(CGThing): # Callee expects a quoted string for the context if # there's a context. context = '"%s"' % context - - if idlNode.isMethod() and idlNode.getExtendedAttribute("WebExtensionStub"): - [ - nativeMethodName, - argsPre, - args, - ] = self.processWebExtensionStubAttribute(idlNode, cgThings) - else: - args = self.getArguments() - cgThings.append( CGCallGenerator( self.needsErrorResult(), needsCallerType(idlNode), isChromeOnly(idlNode), - args, + self.getArguments(), argsPre, returnType, self.extendedAttributes, @@ -9557,95 +9547,6 @@ class CGPerSignatureCall(CGThing): def getArguments(self): return [(a, "arg" + str(i)) for i, a in enumerate(self.arguments)] - def processWebExtensionStubAttribute(self, idlNode, cgThings): - nativeMethodName = "CallWebExtMethod" - stubNameSuffix = idlNode.getExtendedAttribute("WebExtensionStub") - if isinstance(stubNameSuffix, list): - nativeMethodName += stubNameSuffix[0] - - argsLength = len(self.getArguments()) - singleVariadicArg = argsLength == 1 and self.getArguments()[0][0].variadic - - # If the method signature does only include a single variadic arguments, - # then `arg0` is already a Sequence of JS values and we can pass that - # to the WebExtensions Stub method as is. - if singleVariadicArg: - argsPre = [ - "cx", - 'u"%s"_ns' % idlNode.identifier.name, - "Constify(%s)" % "arg0", - ] - args = [] - return [nativeMethodName, argsPre, args] - - argsPre = [ - "cx", - 'u"%s"_ns' % idlNode.identifier.name, - "Constify(%s)" % "args_sequence", - ] - args = [] - - # Determine the maximum number of elements of the js values sequence argument, - # skipping the last optional callback argument if any: - # - # if this WebExtensions API method does expect a last optional callback argument, - # then it is the callback parameter supported for chrome-compatibility - # reasons, and we want it as a separate argument passed to the WebExtension - # stub method and skip it from the js values sequence including all other - # arguments. - maxArgsSequenceLen = argsLength - if argsLength > 0: - lastArg = self.getArguments()[argsLength - 1] - isCallback = lastArg[0].type.tag() == IDLType.Tags.callback - if isCallback and lastArg[0].optional: - argsPre.append( - "MOZ_KnownLive(NonNullHelper(Constify(%s)))" % lastArg[1] - ) - maxArgsSequenceLen = argsLength - 1 - - cgThings.append( - CGGeneric( - dedent( - fill( - """ - // Collecting all args js values into the single sequence argument - // passed to the webextensions stub method. - // - // NOTE: The stub method will receive the original non-normalized js values, - // but those arguments will still be normalized on the main thread by the - // WebExtensions API request handler using the same JSONSchema defnition - // used by the non-webIDL webextensions API bindings. - AutoSequence args_sequence; - SequenceRooter args_sequence_holder(cx, &args_sequence); - - // maximum number of arguments expected by the WebExtensions API method - // excluding the last optional chrome-compatible callback argument (which - // is being passed to the stub method as a separate additional argument). - uint32_t maxArgsSequenceLen = ${maxArgsSequenceLen}; - - uint32_t sequenceArgsLen = args.length() <= maxArgsSequenceLen ? - args.length() : maxArgsSequenceLen; - - if (sequenceArgsLen > 0) { - if (!args_sequence.SetCapacity(sequenceArgsLen, mozilla::fallible)) { - JS_ReportOutOfMemory(cx); - return false; - } - for (uint32_t argIdx = 0; argIdx < sequenceArgsLen; ++argIdx) { - // OK to do infallible append here, since we ensured capacity already. - JS::Value& slot = *args_sequence.AppendElement(); - slot = args[argIdx]; - } - } - """, - maxArgsSequenceLen=maxArgsSequenceLen, - ) - ) - ) - ) - - return [nativeMethodName, argsPre, args] - def needsErrorResult(self): return "needsErrorResult" in self.extendedAttributes diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index f7dab26a5979..85be467fc682 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -6394,7 +6394,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): or identifier == "StaticClassOverride" or identifier == "NonEnumerable" or identifier == "Unexposed" - or identifier == "WebExtensionStub" ): # Known attributes that we don't need to do anything with here pass diff --git a/dom/webidl/ExtensionBrowser.webidl b/dom/webidl/ExtensionBrowser.webidl deleted file mode 100644 index f9a55eba351b..000000000000 --- a/dom/webidl/ExtensionBrowser.webidl +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. - * - * This IDL file is related to interface mixin for the additional globals that should be - * available in windows and service workers allowed to access the WebExtensions API and - * the WebExtensions browser API namespace. - * - * You are granted a license to use, reproduce and create derivative works of - * this document. - */ - -// WebExtensions API interface mixin (used to include ExtensionBrowser interface -// in the ServiceWorkerGlobalScope and Window). -[Exposed=(ServiceWorker)] -interface mixin ExtensionGlobalsMixin { - [Replaceable, SameObject, BinaryName="AcquireExtensionBrowser", - Func="extensions::ExtensionAPIAllowed"] - readonly attribute ExtensionBrowser browser; -}; - -[Exposed=(ServiceWorker), LegacyNoInterfaceObject] -interface ExtensionBrowser { - // A mock API only exposed in tests to unit test the internals - // meant to be reused by the real WebExtensions API bindings - // in xpcshell tests. - [Replaceable, SameObject, BinaryName="GetExtensionMockAPI", - Func="mozilla::extensions::ExtensionMockAPI::IsAllowed", - Pref="extensions.webidl-api.expose_mock_interface"] - readonly attribute ExtensionMockAPI mockExtensionAPI; -}; diff --git a/dom/webidl/ExtensionEventManager.webidl b/dom/webidl/ExtensionEventManager.webidl deleted file mode 100644 index b85b5001a2c4..000000000000 --- a/dom/webidl/ExtensionEventManager.webidl +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. - * - * This IDL file is related to the WebExtensions API object. - * - * You are granted a license to use, reproduce and create derivative works of - * this document. - */ - -[Exposed=(ServiceWorker), LegacyNoInterfaceObject] -interface ExtensionEventManager { - [Throws] - void addListener(Function callback, optional object listenerOptions); - - [Throws] - void removeListener(Function callback); - - [Throws] - boolean hasListener(Function callback); - - [Throws] - boolean hasListeners(); -}; diff --git a/dom/webidl/ExtensionMockAPI.webidl b/dom/webidl/ExtensionMockAPI.webidl deleted file mode 100644 index 34517e3ee16d..000000000000 --- a/dom/webidl/ExtensionMockAPI.webidl +++ /dev/null @@ -1,43 +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/. - * - * You are granted a license to use, reproduce and create derivative works of - * this document. - */ - -// WebIDL definition for the "mockExtensionAPI" WebExtensions API, -// only available in tests and locked behind an about:config preference -// ("extensions.webidl-api.expose_mock_interface"). -[Exposed=(ServiceWorker), LegacyNoInterfaceObject] -interface ExtensionMockAPI { - // Test API methods scenarios. - - [Throws, WebExtensionStub] - any methodSyncWithReturn(any... args); - - [Throws, WebExtensionStub="NoReturn"] - void methodNoReturn(any... args); - - [Throws, WebExtensionStub="Async"] - any methodAsync(any arg0, optional Function cb); - - [Throws, WebExtensionStub="AsyncAmbiguous"] - any methodAmbiguousArgsAsync(any... args); - - [Throws, WebExtensionStub="ReturnsPort"] - ExtensionPort methodReturnsPort(DOMString testName); - - // Test API properties. - - [Replaceable] - readonly attribute any propertyAsErrorObject; - - [Replaceable] - readonly attribute DOMString propertyAsString; - - // Test API events. - - [Replaceable, SameObject] - readonly attribute ExtensionEventManager onTestEvent; -}; diff --git a/dom/webidl/ExtensionPort.webidl b/dom/webidl/ExtensionPort.webidl deleted file mode 100644 index 34b3f85e55ad..000000000000 --- a/dom/webidl/ExtensionPort.webidl +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. - * - * This IDL file is related to the WebExtensions browser.runtime's Port. - * - * You are granted a license to use, reproduce and create derivative works of - * this document. - */ - -[Exposed=(ServiceWorker), LegacyNoInterfaceObject] -interface ExtensionPort { - [Replaceable] - readonly attribute DOMString name; - [Replaceable] - readonly attribute object sender; - [Replaceable] - readonly attribute object? error; - - [Throws, WebExtensionStub="NoReturn"] - void disconnect(); - [Throws, WebExtensionStub="NoReturn"] - void postMessage(any message); - - [Replaceable, SameObject] - readonly attribute ExtensionEventManager onDisconnect; - [Replaceable, SameObject] - readonly attribute ExtensionEventManager onMessage; -}; - -// Dictionary used by ExtensionAPIRequestForwarder and ExtensionCallabck to receive from the -// mozIExtensionAPIRequestHandler an internal description of a runtime.Port (and then used in -// the webidl implementation to create an ExtensionPort instance). -[GenerateInit] -dictionary ExtensionPortDescriptor { - required DOMString portId; - DOMString name = ""; -}; diff --git a/dom/webidl/ServiceWorkerGlobalScope.webidl b/dom/webidl/ServiceWorkerGlobalScope.webidl index f3b0c5bc96e6..f6976bbe3f6f 100644 --- a/dom/webidl/ServiceWorkerGlobalScope.webidl +++ b/dom/webidl/ServiceWorkerGlobalScope.webidl @@ -43,7 +43,3 @@ partial interface ServiceWorkerGlobalScope { attribute EventHandler onnotificationclick; attribute EventHandler onnotificationclose; }; - -// Mixin the WebExtensions API globals (the actual properties are only available to -// extension service workers, locked behind a Func="extensions::ExtensionAPIAllowed" annotation). -ServiceWorkerGlobalScope includes ExtensionGlobalsMixin; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 7cf1419a6381..6634521f7d01 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -379,9 +379,6 @@ with Files("WindowOrWorkerGlobalScope.webidl"): with Files("Worker*"): BUG_COMPONENT = ("Core", "DOM: Workers") -with Files("Extension*"): - BUG_COMPONENT = ("WebExtensions", "General") - GENERATED_WEBIDL_FILES = [ "CSS2Properties.webidl", ] @@ -1051,15 +1048,6 @@ WEBIDL_FILES += [ "StyleSheetApplicableStateChangeEvent.webidl", ] -# WebExtensions API. -WEBIDL_FILES += [ - "ExtensionBrowser.webidl", - "ExtensionEventManager.webidl", - # ExtensionMockAPI is not a real WebExtensions API, and it is only enabled in tests. - "ExtensionMockAPI.webidl", - "ExtensionPort.webidl", -] - # We only expose our prefable test interfaces in debug builds, just to be on # the safe side. if CONFIG["MOZ_DEBUG"] and CONFIG["ENABLE_TESTS"]: diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index c6de6aeaabb0..d1bd6c7d7041 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2217,7 +2217,6 @@ WorkerPrivate::WorkerPrivate( IsNewWorkerSecureContext(mParent, mWorkerKind, mLoadInfo)), mDebuggerRegistered(false), mDebuggerReady(true), - mExtensionAPIAllowed(false), mIsInAutomation(false), mId(std::move(aId)), mAgentClusterOpenerPolicy(aAgentClusterOpenerPolicy), @@ -2289,16 +2288,6 @@ WorkerPrivate::WorkerPrivate( // content processes. mIsPrivilegedAddonGlobal = true; } - - if (StaticPrefs:: - extensions_backgroundServiceWorker_enabled_AtStartup() && - mWorkerKind == WorkerKindService && - policy->IsManifestBackgroundWorker(mScriptURL)) { - // Only allows ExtensionAPI for extension service workers - // that are declared in the extension manifest json as - // the background service worker. - mExtensionAPIAllowed = true; - } } } diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index e375f5847a34..ff6971b3b50a 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -35,7 +35,6 @@ #include "mozilla/dom/WorkerStatus.h" #include "mozilla/dom/workerinternals/JSSettings.h" #include "mozilla/dom/workerinternals/Queue.h" -#include "mozilla/StaticPrefs_extensions.h" #include "nsContentUtils.h" #include "nsIChannel.h" #include "nsIContentSecurityPolicy.h" @@ -169,14 +168,6 @@ class WorkerPrivate final : public RelativeTimeline { return mDebuggerRegistered; } - bool ExtensionAPIAllowed() { - // This method should never be actually called if the extension background - // service worker is disabled by pref. - MOZ_ASSERT( - StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup()); - return mExtensionAPIAllowed; - } - void SetIsDebuggerRegistered(bool aDebuggerRegistered) { AssertIsOnMainThread(); @@ -1341,14 +1332,6 @@ class WorkerPrivate final : public RelativeTimeline { bool mDebuggerReady; nsTArray> mDelayedDebuggeeRunnables; - // Whether this worker should have access to the WebExtension API bindings - // (currently only the Extension Background ServiceWorker declared in the - // extension manifest is allowed to access any WebExtension API bindings). - // This default to false, and it is eventually set to true by - // RemoteWorkerChild::ExecWorkerOnMainThread if the needed conditions - // are met. - bool mExtensionAPIAllowed; - // mIsInAutomation is true when we're running in test automation. // We expose some extra testing functions in that case. bool mIsInAutomation; diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index b721a0ce3bc9..16f2735664f3 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -81,7 +81,6 @@ #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/dom/cache/CacheStorage.h" #include "mozilla/dom/cache/Types.h" -#include "mozilla/extensions/ExtensionBrowser.h" #include "mozilla/fallible.h" #include "mozilla/gfx/Rect.h" #include "nsAtom.h" @@ -796,7 +795,7 @@ void SharedWorkerGlobalScope::Close() { } NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope, - mClients, mExtensionBrowser, mRegistration) + mClients, mRegistration) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerGlobalScope) NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope) @@ -938,15 +937,6 @@ already_AddRefed ServiceWorkerGlobalScope::SkipWaiting( return promise.forget(); } -SafeRefPtr -ServiceWorkerGlobalScope::AcquireExtensionBrowser() { - if (!mExtensionBrowser) { - mExtensionBrowser = MakeSafeRefPtr(this); - } - - return mExtensionBrowser.clonePtr(); -} - bool WorkerDebuggerGlobalScope::WrapGlobalObject( JSContext* aCx, JS::MutableHandle aReflector) { mWorkerPrivate->AssertIsOnWorkerThread(); diff --git a/dom/workers/WorkerScope.h b/dom/workers/WorkerScope.h index 24d8ff2379f0..5604e40294fb 100644 --- a/dom/workers/WorkerScope.h +++ b/dom/workers/WorkerScope.h @@ -16,7 +16,6 @@ #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" #include "mozilla/dom/ImageBitmapSource.h" -#include "mozilla/dom/SafeRefPtr.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsIGlobalObject.h" @@ -33,12 +32,6 @@ class nsISerialEventTarget; namespace mozilla { class ErrorResult; -namespace extensions { - -class ExtensionBrowser; - -} // namespace extensions - namespace dom { class AnyCallback; @@ -374,8 +367,6 @@ class ServiceWorkerGlobalScope final : public WorkerGlobalScope { already_AddRefed SkipWaiting(ErrorResult& aRv); - SafeRefPtr AcquireExtensionBrowser(); - IMPL_EVENT_HANDLER(install) IMPL_EVENT_HANDLER(activate) @@ -402,7 +393,6 @@ class ServiceWorkerGlobalScope final : public WorkerGlobalScope { RefPtr mClients; const nsString mScope; RefPtr mRegistration; - SafeRefPtr mExtensionBrowser; }; class WorkerDebuggerGlobalScope final : public WorkerGlobalScopeBase { diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 143a8a885dba..2a0b2c5ed341 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -3955,16 +3955,6 @@ value: false mirror: always -# Whether to expose the MockExtensionAPI test interface in tests. -# The interface MockExtensionAPI doesn't represent a real extension API, -# it is only available in test and does include a series of cases useful -# to test the API request handling without tying the unit test to a -# specific WebExtensions API. -- name: extensions.webidl-api.expose_mock_interface - type: RelaxedAtomicBool - value: false - mirror: always - #--------------------------------------------------------------------------- # Prefs starting with "findbar." #--------------------------------------------------------------------------- diff --git a/toolkit/components/extensions/ExtensionPolicyService.cpp b/toolkit/components/extensions/ExtensionPolicyService.cpp index 399ffd992b24..ebdc3b8ec1d2 100644 --- a/toolkit/components/extensions/ExtensionPolicyService.cpp +++ b/toolkit/components/extensions/ExtensionPolicyService.cpp @@ -54,16 +54,9 @@ using dom::Promise; static const char kDocElementInserted[] = "initial-document-element-inserted"; -/***************************************************************************** - * ExtensionPolicyService - *****************************************************************************/ - -/* static */ -mozIExtensionProcessScript& ExtensionPolicyService::ProcessScript() { +static mozIExtensionProcessScript& ProcessScript() { static nsCOMPtr sProcessScript; - MOZ_ASSERT(NS_IsMainThread()); - if (MOZ_UNLIKELY(!sProcessScript)) { sProcessScript = do_ImportModule("resource://gre/modules/ExtensionProcessScript.jsm", @@ -74,6 +67,10 @@ mozIExtensionProcessScript& ExtensionPolicyService::ProcessScript() { return *sProcessScript; } +/***************************************************************************** + * ExtensionPolicyService + *****************************************************************************/ + /* static */ ExtensionPolicyService& ExtensionPolicyService::GetSingleton() { static RefPtr sExtensionPolicyService; diff --git a/toolkit/components/extensions/ExtensionPolicyService.h b/toolkit/components/extensions/ExtensionPolicyService.h index df7859ea3721..9e7acde9dc8f 100644 --- a/toolkit/components/extensions/ExtensionPolicyService.h +++ b/toolkit/components/extensions/ExtensionPolicyService.h @@ -8,7 +8,6 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/extensions/WebExtensionPolicy.h" -#include "mozIExtensionProcessScript.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsHashKeys.h" @@ -52,8 +51,6 @@ class ExtensionPolicyService final : public nsIAddonPolicyService, NS_DECL_NSIOBSERVER NS_DECL_NSIMEMORYREPORTER - static mozIExtensionProcessScript& ProcessScript(); - static ExtensionPolicyService& GetSingleton(); static already_AddRefed GetInstance() { diff --git a/toolkit/components/extensions/ExtensionProcessScript.jsm b/toolkit/components/extensions/ExtensionProcessScript.jsm index afe39be5a755..457b5c8e17e2 100644 --- a/toolkit/components/extensions/ExtensionProcessScript.jsm +++ b/toolkit/components/extensions/ExtensionProcessScript.jsm @@ -10,7 +10,7 @@ * after startup, in *every* browser process live outside of this file. */ -var EXPORTED_SYMBOLS = ["ExtensionProcessScript", "ExtensionAPIRequestHandler"]; +var EXPORTED_SYMBOLS = ["ExtensionProcessScript"]; const { MessageChannel } = ChromeUtils.import( "resource://gre/modules/MessageChannel.jsm" @@ -417,14 +417,4 @@ var ExtensionProcessScript = { }, }; -var ExtensionAPIRequestHandler = { - handleAPIRequest(policy, request) { - // 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"); - }, -}; - ExtensionManager.init(); diff --git a/toolkit/components/extensions/moz.build b/toolkit/components/extensions/moz.build index 721dfa2e7eba..0b535592dab7 100755 --- a/toolkit/components/extensions/moz.build +++ b/toolkit/components/extensions/moz.build @@ -65,7 +65,6 @@ TESTING_JS_MODULES += [ DIRS += [ "schemas", "storage", - "webidl-api", "webrequest", ] @@ -75,7 +74,6 @@ IPDL_SOURCES += [ XPIDL_SOURCES += [ "extIWebNavigation.idl", - "mozIExtensionAPIRequestHandling.idl", "mozIExtensionProcessScript.idl", ] @@ -130,11 +128,6 @@ XPCSHELL_TESTS_MANIFESTS += [ "test/xpcshell/xpcshell.ini", ] -# Only include tests that requires the WebExtensions WebIDL API bindings -# in builds where they are enabled (currently only on Nightly builds). -if CONFIG["MOZ_WEBEXT_WEBIDL_ENABLED"]: - XPCSHELL_TESTS_MANIFESTS += ["test/xpcshell/webidl-api/xpcshell.ini"] - SPHINX_TREES["webextensions"] = "docs" with Files("docs/**"): diff --git a/toolkit/components/extensions/mozIExtensionAPIRequestHandling.idl b/toolkit/components/extensions/mozIExtensionAPIRequestHandling.idl deleted file mode 100644 index dc746df8193d..000000000000 --- a/toolkit/components/extensions/mozIExtensionAPIRequestHandling.idl +++ /dev/null @@ -1,151 +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/. */ - -#include "nsISupports.idl" - -interface nsIPrincipal; - -[scriptable, builtinclass, uuid(e6862533-8844-4207-a6ab-04748a29d859)] -interface mozIExtensionServiceWorkerInfo : nsISupports -{ - readonly attribute nsIPrincipal principal; - readonly attribute AString scriptURL; - readonly attribute AString clientInfoId; -}; - -[scriptable, uuid(876d45db-5c1b-4c9b-9148-1c86b33d120b)] -interface mozIExtensionListenerCallOptions : nsISupports -{ - cenum APIObjectType: 8 { - // Default: no api object is prepended to the event listener call arguments. - NONE, - - // A runtime.Port instance is prepended to the event listener call arguments. - RUNTIME_PORT, - }; - - readonly attribute mozIExtensionListenerCallOptions_APIObjectType apiObjectType; - - // An optional javascript object that should provide the attributes expected - // by related apiObjectType webidl dictionary type (e.g. ExtensionPortDescriptor - // if apiObjectType is RUNTIME_PORT). - readonly attribute jsval apiObjectDescriptor; - - cenum CallbackType: 8 { - // Default: no callback argument is passed to the call to the event listener. - CALLBACK_NONE, - - // The event listener will be called with a function as the last call parameter - // that behaves like the runtime.onMessage's sendResponse parameter: - // - // - if the event listener already returned false, sendResponse calls are ignored - // (if it has not been called already) - // - if the event listener already returned true, the first sendResponse call - // resolves the promise returned by the mozIExtensionCallback method call - // - if the event listener already returned a Promise, sendResponse calls - // are ignored - CALLBACK_SEND_RESPONSE, - }; - - attribute mozIExtensionListenerCallOptions_CallbackType callbackType; -}; - -[scriptable, builtinclass, uuid(e68e3c19-1b35-4112-8faa-5c5b84086a5b)] -interface mozIExtensionEventListener : nsISupports -{ - [implicit_jscontext, can_run_script] - Promise callListener( - in Array args, - [optional] in mozIExtensionListenerCallOptions listenerCallOptions); -}; - -[scriptable, builtinclass, uuid(0fee1c8f-e363-46a6-bd0c-d3c3338e2534)] -interface mozIExtensionAPIRequest : nsISupports -{ - AUTF8String toString(); - - // Determine what the caller and receiver should expect, e.g. what should - // be provided to the API request handler and what to expect it to return. - cenum RequestType: 8 { - CALL_FUNCTION, - CALL_FUNCTION_NO_RETURN, - CALL_FUNCTION_ASYNC, - ADD_LISTENER, - REMOVE_LISTENER, - GET_PROPERTY, - }; - - // The type of the request. - readonly attribute AUTF8String requestType; - - // WebExtension API namespace (e.g. tabs, runtime, webRequest, ...) - readonly attribute AUTF8String apiNamespace; - // method or event name - readonly attribute AUTF8String apiName; - - // API object type (e.g. Port, Panel, ...) and its unique id, this - // properties are used by API requests originated by an API object - // instance (like a runtime Port returned by browser.runtime.connect). - readonly attribute AUTF8String apiObjectType; - readonly attribute AUTF8String apiObjectId; - - // An array of API call arguments. - [implicit_jscontext] readonly attribute jsval args; - - // The caller SavedFrame (only set for calls originated off of the main thread - // from a service worker). - [implicit_jscontext] readonly attribute jsval callerSavedFrame; - - // Set for requests coming from an extension service worker. - readonly attribute mozIExtensionServiceWorkerInfo serviceWorkerInfo; - - // Set for `addListener`/`removeListener` API requests. - readonly attribute mozIExtensionEventListener eventListener; -}; - -[scriptable, uuid(59fd4097-d88e-40fd-8664-fedd8ab67ab6)] -interface mozIExtensionAPIRequestResult : nsISupports -{ - cenum ResultType: 8 { - // The result is a value to be returned as a result for the API request. - // The value attribute can be set to: - // - a structured clonable result value (which may be the result of the - // API call itself, or be used by the API method webidl implementation - // to initialize a webidl object to return to the caller, e.g. - // ExtensionPort returned by a call to browser.runtime.connect()) - // - an error object (which also include internally converted to and from - // ClonedErrorHolder to make it structured clonable). - // - a Promise (which can be resolved to a structured clonable value or - // an error object). - RETURN_VALUE, - - // The result is an error object that should be thrown as an extension error - // to the caller on the thread that originated the request. - EXTENSION_ERROR, - }; - - readonly attribute mozIExtensionAPIRequestResult_ResultType type; - readonly attribute jsval value; -}; - -[scriptable, uuid(0c61bd33-0557-43a2-9497-96c449f39e33)] -interface mozIExtensionAPIRequestHandler : nsISupports -{ - /** - * Handle an API request originated from the WebExtensions webidl API - * bindings. - * - * @param extension An instance of the WebExtensionPolicy webidl interface. - * @param apiRequest An instance of the mozIExtensionAPIRequest xpcom interface. - * - * @return mozIExtensionAPIRequestResult - * JS value returned by the API request handler, may contain a value - * (the result of the API call or a WebIDL dictionary that is used to - * initialize WebIDL-based API object, e.g. ExtensionPort) or - * an Error to be throw on the thread that originated the request. - */ - void handleAPIRequest(in nsISupports extension, - in mozIExtensionAPIRequest apiRequest, - [optional, retval] out mozIExtensionAPIRequestResult apiRequestResult); -}; diff --git a/toolkit/components/extensions/test/xpcshell/webidl-api/.eslintrc.js b/toolkit/components/extensions/test/xpcshell/webidl-api/.eslintrc.js deleted file mode 100644 index 3622fff4f6a2..000000000000 --- a/toolkit/components/extensions/test/xpcshell/webidl-api/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -module.exports = { - env: { - // The tests in this folder are testing based on WebExtensions, so lets - // just define the webextensions environment here. - webextensions: true, - }, -}; diff --git a/toolkit/components/extensions/test/xpcshell/webidl-api/head_webidl_api.js b/toolkit/components/extensions/test/xpcshell/webidl-api/head_webidl_api.js deleted file mode 100644 index a53fe6b91bee..000000000000 --- a/toolkit/components/extensions/test/xpcshell/webidl-api/head_webidl_api.js +++ /dev/null @@ -1,309 +0,0 @@ -/* import-globals-from ../head.js */ - -/* exported getBackgroundServiceWorkerRegistration, waitForTerminatedWorkers, - * runExtensionAPITest */ - -"use strict"; - -XPCOMUtils.defineLazyModuleGetters(this, { - TestUtils: "resource://testing-common/TestUtils.jsm", - ExtensionTestCommon: "resource://testing-common/ExtensionTestCommon.jsm", -}); - -add_task(function checkExtensionsWebIDLEnabled() { - equal( - AppConstants.MOZ_WEBEXT_WEBIDL_ENABLED, - true, - "WebExtensions WebIDL bindings build time flag should be enabled" - ); -}); - -function getBackgroundServiceWorkerRegistration(extension) { - const swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService( - Ci.nsIServiceWorkerManager - ); - - const swRegs = swm.getAllRegistrations(); - const scope = `moz-extension://${extension.uuid}/`; - - for (let i = 0; i < swRegs.length; i++) { - let regInfo = swRegs.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo); - if (regInfo.scope === scope) { - return regInfo; - } - } -} - -function waitForTerminatedWorkers(swRegInfo) { - info(`Wait all ${swRegInfo.scope} workers to be terminated`); - return TestUtils.waitForCondition(() => { - const { - evaluatingWorker, - installingWorker, - waitingWorker, - activeWorker, - } = swRegInfo; - return !( - evaluatingWorker || - installingWorker || - waitingWorker || - activeWorker - ); - }, `wait workers for scope ${swRegInfo.scope} to be terminated`); -} - -function unmockHandleAPIRequest(extPage) { - return extPage.spawn([], () => { - const { ExtensionAPIRequestHandler } = ChromeUtils.import( - "resource://gre/modules/ExtensionProcessScript.jsm" - ); - - // Unmock ExtensionAPIRequestHandler. - if (ExtensionAPIRequestHandler._handleAPIRequest_orig) { - ExtensionAPIRequestHandler.handleAPIRequest = - ExtensionAPIRequestHandler._handleAPIRequest_orig; - delete ExtensionAPIRequestHandler._handleAPIRequest_orig; - } - }); -} - -function mockHandleAPIRequest(extPage, mockHandleAPIRequest) { - mockHandleAPIRequest = - mockHandleAPIRequest || - ((policy, request) => { - const ExtError = request.window?.Error || Error; - return { - type: Ci.mozIExtensionAPIRequestResult.EXTENSION_ERROR, - value: new ExtError( - "mockHandleAPIRequest not defined by this test case" - ), - }; - }); - - return extPage.spawn( - [ExtensionTestCommon.serializeFunction(mockHandleAPIRequest)], - mockFnText => { - const { ExtensionAPIRequestHandler } = ChromeUtils.import( - "resource://gre/modules/ExtensionProcessScript.jsm" - ); - - mockFnText = `(() => { - return (${mockFnText}); - })();`; - // eslint-disable-next-line no-eval - const mockFn = eval(mockFnText); - - // Mock ExtensionAPIRequestHandler. - if (!ExtensionAPIRequestHandler._handleAPIRequest_orig) { - ExtensionAPIRequestHandler._handleAPIRequest_orig = - ExtensionAPIRequestHandler.handleAPIRequest; - } - - ExtensionAPIRequestHandler.handleAPIRequest = function(policy, request) { - if (request.apiNamespace === "test") { - return this._handleAPIRequest_orig(policy, request); - } - return mockFn.call(this, policy, request); - }; - } - ); -} - -/** - * An helper function used to run unit test that are meant to test the - * Extension API webidl bindings helpers shared by all the webextensions - * API namespaces. - * - * @param {string} testDescription - * Brief description of the test. - * @param {Object} [options] - * @param {Function} backgroundScript - * Test function running in the extension global. This function - * does receive a parameter of type object with the following - * properties: - * - testLog(message): log a message on the terminal - * - testAsserts: - * - isErrorInstance(err): throw if err is not an Error instance - * - isInstanceOf(value, globalContructorName): throws if value - * is not an instance of global[globalConstructorName] - * - equal(val, exp, msg): throw an error including msg if - * val is not strictly equal to exp. - * @param {Function} assertResults - * Function to be provided to assert the result returned by - * `backgroundScript`, or assert the error if it did throw. - * This function does receive a parameter of type object with - * the following properties: - * - testResult: the result returned (and resolved if the return - * value was a promise) from the call to `backgroundScript` - * - testError: the error raised (or rejected if the return value - * value was a promise) from the call to `backgroundScript` - * @param {Function} mockAPIRequestHandler - * Function to be used to mock mozIExtensionAPIRequestHandler.handleAPIRequest - * for the purpose of the test. - * This function received the same parameter that are listed in the idl - * definition (mozIExtensionAPIRequestHandling.webidl). - * @param {string} [options.extensionId] - * Optional extension id for the test extension. - */ -async function runExtensionAPITest( - testDescription, - { - backgroundScript, - assertResults, - mockAPIRequestHandler, - extensionId = "test-ext-api-request-forward@mochitest", - } -) { - // Wraps the `backgroundScript` function to be execute in the target - // extension global (currently only in a background service worker, - // in follow-ups the same function should also be execute in - // other supported extension globals, e.g. an extension page and - // a content script). - // - // The test wrapper does also provide to `backgroundScript` some - // helpers to be used as part of the test, these tests are meant to - // only cover internals shared by all webidl API bindings through a - // mock API namespace only available in tests (and so none of the tests - // written with this helpers should be using the browser.test API namespace). - function backgroundScriptWrapper(testParams, testFn) { - const testLog = msg => { - // console messages emitted by workers are not visible in the test logs if not - // explicitly collected, and so this testLog helper method does use dump for now - // (this way the logs will be visibile as part of the test logs). - dump(`"${testParams.extensionId}": ${msg}\n`); - }; - - const testAsserts = { - isErrorInstance(err) { - if (!(err instanceof Error)) { - throw new Error("Unexpected error: not an instance of Error"); - } - return true; - }, - isInstanceOf(value, globalConstructorName) { - if (!(value instanceof self[globalConstructorName])) { - throw new Error( - `Unexpected error: expected instance of ${globalConstructorName}` - ); - } - return true; - }, - equal(val, exp, msg) { - if (val !== exp) { - throw new Error( - `Unexpected error: expected ${exp} but got ${val}. ${msg}` - ); - } - }, - }; - - testLog(`Evaluating - test case "${testParams.testDescription}"`); - self.onmessage = async evt => { - testLog(`Running test case "${testParams.testDescription}"`); - - let testError = null; - let testResult; - try { - testResult = await testFn({ testLog, testAsserts }); - } catch (err) { - testError = { message: err.message, stack: err.stack }; - testLog(`Unexpected test error: ${err} :: ${err.stack}\n`); - } - - evt.ports[0].postMessage({ success: !testError, testError, testResult }); - - testLog(`Test case "${testParams.testDescription}" executed`); - }; - testLog(`Wait onmessage event - test case "${testParams.testDescription}"`); - } - - async function assertTestResult(result) { - if (assertResults) { - await assertResults(result); - } else { - equal(result.testError, undefined, "Expect no errors"); - ok(result.success, "Test completed successfully"); - } - } - - async function runTestCaseInWorker(page) { - info(`*** Run test case in an extension service worker`); - const result = await page.spawn([], async () => { - const { active } = await content.navigator.serviceWorker.ready; - const { port1, port2 } = new MessageChannel(); - - return new Promise(resolve => { - port1.onmessage = evt => resolve(evt.data); - active.postMessage("run-test", [port2]); - }); - }); - info(`*** Assert test case results got from extension service worker`); - await assertTestResult(result); - } - - // NOTE: prefixing this with `function ` is needed because backgroundScript - // is an object property and so it is going to be stringified as - // `backgroundScript() { ... }` (which would be detected as a syntax error - // on the worker script evaluation phase). - const scriptFnParam = ExtensionTestCommon.serializeFunction(backgroundScript); - const testOptsParam = `${JSON.stringify({ testDescription, extensionId })}`; - - const testExtData = { - useAddonManager: "temporary", - manifest: { - version: "1", - background: { - service_worker: "test-sw.js", - }, - applications: { - gecko: { id: extensionId }, - }, - }, - files: { - "page.html": ` - - - - `, - "test-sw.js": ` - (${backgroundScriptWrapper})(${testOptsParam}, ${scriptFnParam}); - `, - }, - }; - - let cleanupCalled = false; - let extension; - let page; - let swReg; - - async function testCleanup() { - if (cleanupCalled) { - return; - } - - cleanupCalled = true; - await unmockHandleAPIRequest(page); - await page.close(); - await extension.unload(); - await waitForTerminatedWorkers(swReg); - } - - info(`Start test case "${testDescription}"`); - extension = ExtensionTestUtils.loadExtension(testExtData); - await extension.startup(); - - swReg = getBackgroundServiceWorkerRegistration(extension); - ok(swReg, "Extension background.service_worker should be registered"); - - page = await ExtensionTestUtils.loadContentPage( - `moz-extension://${extension.uuid}/page.html`, - { extension } - ); - - registerCleanupFunction(testCleanup); - - await mockHandleAPIRequest(page, mockAPIRequestHandler); - await runTestCaseInWorker(page); - await testCleanup(); - info(`End test case "${testDescription}"`); -} diff --git a/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api.js b/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api.js deleted file mode 100644 index 926fde93d59c..000000000000 --- a/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api.js +++ /dev/null @@ -1,489 +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" - ); -}); - -add_task(async function test_ext_context_does_have_webidl_bindings() { - await runExtensionAPITest("should have a browser global object", { - backgroundScript() { - const { browser } = self; - - return { - hasExtensionAPI: !!browser, - hasExtensionMockAPI: !!browser?.mockExtensionAPI, - }; - }, - assertResults({ testResult, testError }) { - Assert.deepEqual(testError, undefined); - Assert.deepEqual( - testResult, - { - hasExtensionAPI: true, - hasExtensionMockAPI: true, - }, - "browser and browser.test WebIDL API bindings found" - ); - }, - }); -}); - -add_task(async function test_propagated_extension_error() { - await runExtensionAPITest( - "should throw an extension error on ResultType::EXTENSION_ERROR", - { - backgroundScript({ testAsserts }) { - try { - const api = self.browser.mockExtensionAPI; - api.methodSyncWithReturn("arg0", 1, { value: "arg2" }); - } catch (err) { - testAsserts.isErrorInstance(err); - throw err; - } - }, - mockAPIRequestHandler(policy, request) { - return { - type: Ci.mozIExtensionAPIRequestResult.EXTENSION_ERROR, - value: new Error("Fake Extension Error"), - }; - }, - assertResults({ testError }) { - Assert.deepEqual(testError?.message, "Fake Extension Error"); - }, - } - ); -}); - -add_task(async function test_system_errors_donot_leak() { - function assertResults({ testError }) { - ok( - testError?.message?.match(/An unexpected error occurred/), - `Got the general unexpected error as expected: ${testError?.message}` - ); - } - - function mockAPIRequestHandler(policy, request) { - throw new Error("Fake handleAPIRequest exception"); - } - - const msg = - "should throw an unexpected error occurred if handleAPIRequest throws"; - - await runExtensionAPITest(`sync method ${msg}`, { - backgroundScript({ testAsserts }) { - try { - self.browser.mockExtensionAPI.methodSyncWithReturn("arg0"); - } catch (err) { - testAsserts.isErrorInstance(err); - throw err; - } - }, - mockAPIRequestHandler, - assertResults, - }); - - await runExtensionAPITest(`async method ${msg}`, { - backgroundScript({ testAsserts }) { - try { - self.browser.mockExtensionAPI.methodAsync("arg0"); - } catch (err) { - testAsserts.isErrorInstance(err); - throw err; - } - }, - mockAPIRequestHandler, - assertResults, - }); - - await runExtensionAPITest(`no return method ${msg}`, { - backgroundScript({ testAsserts }) { - try { - self.browser.mockExtensionAPI.methodNoReturn("arg0"); - } catch (err) { - testAsserts.isErrorInstance(err); - throw err; - } - }, - mockAPIRequestHandler, - assertResults, - }); -}); - -add_task(async function test_call_sync_function_result() { - await runExtensionAPITest( - "sync API methods should support structured clonable return values", - { - backgroundScript({ testAsserts }) { - const api = self.browser.mockExtensionAPI; - const results = { - string: api.methodSyncWithReturn("string-result"), - nested_prop: api.methodSyncWithReturn({ - string: "123", - number: 123, - date: new Date("2020-09-20"), - map: new Map([ - ["a", 1], - ["b", 2], - ]), - }), - }; - - testAsserts.isInstanceOf(results.nested_prop.date, "Date"); - testAsserts.isInstanceOf(results.nested_prop.map, "Map"); - return results; - }, - mockAPIRequestHandler(policy, request) { - if (request.apiName === "methodSyncWithReturn") { - // Return the first argument unmodified, which will be checked in the - // resultAssertFn above. - return { - type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE, - value: request.args[0], - }; - } - throw new Error("Unexpected API method"); - }, - assertResults({ testResult, testError }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual(testResult, { - string: "string-result", - nested_prop: { - string: "123", - number: 123, - date: new Date("2020-09-20"), - map: new Map([ - ["a", 1], - ["b", 2], - ]), - }, - }); - }, - } - ); -}); - -add_task(async function test_call_sync_fn_missing_return() { - await runExtensionAPITest( - "should throw an unexpected error occurred on missing return value", - { - backgroundScript() { - self.browser.mockExtensionAPI.methodSyncWithReturn("arg0"); - }, - mockAPIRequestHandler(policy, request) { - return undefined; - }, - assertResults({ testError }) { - ok( - testError?.message?.match(/An unexpected error occurred/), - `Got the general unexpected error as expected: ${testError?.message}` - ); - }, - } - ); -}); - -add_task(async function test_call_async_throw_extension_error() { - await runExtensionAPITest( - "an async function can throw an error occurred for param validation errors", - { - backgroundScript({ testAsserts }) { - try { - self.browser.mockExtensionAPI.methodAsync("arg0"); - } catch (err) { - testAsserts.isErrorInstance(err); - throw err; - } - }, - mockAPIRequestHandler(policy, request) { - return { - type: Ci.mozIExtensionAPIRequestResult.EXTENSION_ERROR, - value: new Error("Fake Param Validation Error"), - }; - }, - assertResults({ testError }) { - Assert.deepEqual(testError?.message, "Fake Param Validation Error"); - }, - } - ); -}); - -add_task(async function test_call_async_reject_error() { - await runExtensionAPITest( - "an async function rejected promise should propagate extension errors", - { - async backgroundScript({ testAsserts }) { - try { - await self.browser.mockExtensionAPI.methodAsync("arg0"); - } catch (err) { - testAsserts.isErrorInstance(err); - throw err; - } - }, - mockAPIRequestHandler(policy, request) { - return { - type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE, - value: Promise.reject(new Error("Fake API rejected error object")), - }; - }, - assertResults({ testError }) { - Assert.deepEqual(testError?.message, "Fake API rejected error object"); - }, - } - ); -}); - -add_task(async function test_call_async_function_result() { - await runExtensionAPITest( - "async API methods should support structured clonable resolved values", - { - async backgroundScript({ testAsserts }) { - const api = self.browser.mockExtensionAPI; - const results = { - string: await api.methodAsync("string-result"), - nested_prop: await api.methodAsync({ - string: "123", - number: 123, - date: new Date("2020-09-20"), - map: new Map([ - ["a", 1], - ["b", 2], - ]), - }), - }; - - testAsserts.isInstanceOf(results.nested_prop.date, "Date"); - testAsserts.isInstanceOf(results.nested_prop.map, "Map"); - return results; - }, - mockAPIRequestHandler(policy, request) { - if (request.apiName === "methodAsync") { - // Return the first argument unmodified, which will be checked in the - // resultAssertFn above. - return { - type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE, - value: Promise.resolve(request.args[0]), - }; - } - throw new Error("Unexpected API method"); - }, - assertResults({ testResult, testError }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual(testResult, { - string: "string-result", - nested_prop: { - string: "123", - number: 123, - date: new Date("2020-09-20"), - map: new Map([ - ["a", 1], - ["b", 2], - ]), - }, - }); - }, - } - ); -}); - -add_task(async function test_call_no_return_throw_extension_error() { - await runExtensionAPITest( - "no return function call throw an error occurred for param validation errors", - { - backgroundScript({ testAsserts }) { - try { - self.browser.mockExtensionAPI.methodNoReturn("arg0"); - } catch (err) { - testAsserts.isErrorInstance(err); - throw err; - } - }, - mockAPIRequestHandler(policy, request) { - return { - type: Ci.mozIExtensionAPIRequestResult.EXTENSION_ERROR, - value: new Error("Fake Param Validation Error"), - }; - }, - assertResults({ testError }) { - Assert.deepEqual(testError?.message, "Fake Param Validation Error"); - }, - } - ); -}); - -add_task(async function test_call_no_return_without_errors() { - await runExtensionAPITest( - "handleAPIHandler can return undefined on api calls to methods with no return", - { - backgroundScript() { - self.browser.mockExtensionAPI.methodNoReturn("arg0"); - }, - mockAPIRequestHandler(policy, request) { - return undefined; - }, - assertResults({ testError }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - }, - } - ); -}); - -add_task(async function test_async_method_chrome_compatible_callback() { - function mockAPIRequestHandler(policy, request) { - if (request.args[0] === "fake-async-method-failure") { - return { - type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE, - value: Promise.reject("this-should-not-be-passed-to-cb-as-parameter"), - }; - } - - return { - type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE, - value: Promise.resolve(request.args), - }; - } - - await runExtensionAPITest( - "async method should support an optional chrome-compatible callback", - { - mockAPIRequestHandler, - async backgroundScript({ testAsserts }) { - const api = self.browser.mockExtensionAPI; - const success_cb_params = await new Promise(resolve => { - const res = api.methodAsync( - { prop: "fake-async-method-success" }, - (...results) => { - resolve(results); - } - ); - testAsserts.equal(res, undefined, "no promise should be returned"); - }); - const error_cb_params = await new Promise(resolve => { - const res = api.methodAsync( - "fake-async-method-failure", - (...results) => { - resolve(results); - } - ); - testAsserts.equal(res, undefined, "no promise should be returned"); - }); - return { success_cb_params, error_cb_params }; - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual( - testResult, - { - success_cb_params: [[{ prop: "fake-async-method-success" }]], - error_cb_params: [], - }, - "Got the expected results from the chrome compatible callbacks" - ); - }, - } - ); - - await runExtensionAPITest( - "async method with ambiguous args called with a chrome-compatible callback", - { - mockAPIRequestHandler, - async backgroundScript({ testAsserts }) { - const api = self.browser.mockExtensionAPI; - const success_cb_params = await new Promise(resolve => { - const res = api.methodAmbiguousArgsAsync( - "arg0", - { prop: "arg1" }, - 3, - (...results) => { - resolve(results); - } - ); - testAsserts.equal(res, undefined, "no promise should be returned"); - }); - const error_cb_params = await new Promise(resolve => { - const res = api.methodAmbiguousArgsAsync( - "fake-async-method-failure", - (...results) => { - resolve(results); - } - ); - testAsserts.equal(res, undefined, "no promise should be returned"); - }); - return { success_cb_params, error_cb_params }; - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual( - testResult, - { - success_cb_params: [["arg0", { prop: "arg1" }, 3]], - error_cb_params: [], - }, - "Got the expected results from the chrome compatible callbacks" - ); - }, - } - ); -}); - -add_task(async function test_get_property() { - await runExtensionAPITest( - "getProperty API request does return a value synchrously", - { - backgroundScript() { - return self.browser.mockExtensionAPI.propertyAsString; - }, - mockAPIRequestHandler(policy, request) { - return { - type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE, - value: "property-value", - }; - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual( - testResult, - "property-value", - "Got the expected result" - ); - }, - } - ); - - await runExtensionAPITest( - "getProperty API request can return an error object", - { - backgroundScript({ testAsserts }) { - const errObj = self.browser.mockExtensionAPI.propertyAsErrorObject; - testAsserts.isErrorInstance(errObj); - testAsserts.equal(errObj.message, "fake extension error"); - }, - mockAPIRequestHandler(policy, request) { - let savedFrame = request.calledSavedFrame; - return { - type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE, - value: ChromeUtils.createError("fake extension error", savedFrame), - }; - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - }, - } - ); -}); diff --git a/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api_event_callback.js b/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api_event_callback.js deleted file mode 100644 index 32a18cd09623..000000000000 --- a/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api_event_callback.js +++ /dev/null @@ -1,421 +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" - ); -}); - -add_task(async function test_api_event_manager_methods() { - await runExtensionAPITest("extension event manager methods", { - backgroundScript({ testAsserts, testLog }) { - const api = browser.mockExtensionAPI; - const listener = () => {}; - - function assertHasListener(expect) { - testAsserts.equal( - api.onTestEvent.hasListeners(), - expect, - `onTestEvent.hasListeners should return {expect}` - ); - testAsserts.equal( - api.onTestEvent.hasListener(listener), - expect, - `onTestEvent.hasListeners should return {expect}` - ); - } - - assertHasListener(false); - api.onTestEvent.addListener(listener); - assertHasListener(true); - api.onTestEvent.removeListener(listener); - assertHasListener(false); - }, - mockAPIRequestHandler(policy, request) { - if (!request.eventListener) { - throw new Error( - "Unexpected Error: missing ExtensionAPIRequest.eventListener" - ); - } - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - }, - }); -}); - -add_task(async function test_api_event_eventListener_call() { - await runExtensionAPITest( - "extension event eventListener wrapper does forward calls parameters", - { - backgroundScript({ testAsserts, testLog }) { - const api = browser.mockExtensionAPI; - let listener; - - return new Promise((resolve, reject) => { - testLog("addListener and wait for event to be fired"); - listener = (...args) => { - testLog("onTestEvent"); - // Make sure the extension code can access the arguments. - try { - testAsserts.equal(args[1], "arg1"); - resolve(args); - } catch (err) { - reject(err); - } - }; - api.onTestEvent.addListener(listener); - }); - }, - mockAPIRequestHandler(policy, request) { - if (!request.eventListener) { - throw new Error( - "Unexpected Error: missing ExtensionAPIRequest.eventListener" - ); - } - if (request.requestType === "addListener") { - let args = [{ arg: 0 }, "arg1"]; - request.eventListener.callListener(args); - } - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual( - testResult, - [{ arg: 0 }, "arg1"], - "Got the expected result" - ); - }, - } - ); -}); - -add_task(async function test_api_event_eventListener_call_with_result() { - await runExtensionAPITest( - "extension event eventListener wrapper forwarded call result", - { - backgroundScript({ testAsserts, testLog }) { - const api = browser.mockExtensionAPI; - let listener; - - return new Promise((resolve, reject) => { - testLog("addListener and wait for event to be fired"); - listener = (msg, value) => { - testLog(`onTestEvent received: ${msg}`); - switch (msg) { - case "test-result-value": - return value; - case "test-promise-resolve": - return Promise.resolve(value); - case "test-promise-reject": - return Promise.reject(new Error("test-reject")); - case "test-done": - resolve(value); - break; - default: - reject(new Error(`Unexpected onTestEvent message: ${msg}`)); - } - }; - api.onTestEvent.addListener(listener); - }); - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual( - testResult?.resSync, - { prop: "retval" }, - "Got result from eventListener returning a plain return value" - ); - Assert.deepEqual( - testResult?.resAsync, - { prop: "promise" }, - "Got result from eventListener returning a resolved promise" - ); - Assert.deepEqual( - testResult?.resAsyncReject, - { - isInstanceOfError: true, - errorMessage: "test-reject", - }, - "got result from eventListener returning a rejected promise" - ); - }, - mockAPIRequestHandler(policy, request) { - if (!request.eventListener) { - throw new Error( - "Unexpected Error: missing ExtensionAPIRequest.eventListener" - ); - } - - if (request.requestType === "addListener") { - Promise.resolve().then(async () => { - try { - dump(`calling listener, expect a plain return value\n`); - const resSync = await request.eventListener.callListener([ - "test-result-value", - { prop: "retval" }, - ]); - - dump( - `calling listener, expect a resolved promise return value\n` - ); - const resAsync = await request.eventListener.callListener([ - "test-promise-resolve", - { prop: "promise" }, - ]); - - dump( - `calling listener, expect a rejected promise return value\n` - ); - const resAsyncReject = await request.eventListener - .callListener(["test-promise-reject"]) - .catch(err => err); - - // call API listeners once more to complete the test - let args = { - resSync, - resAsync, - resAsyncReject: { - isInstanceOfError: resAsyncReject instanceof Error, - errorMessage: resAsyncReject?.message, - }, - }; - request.eventListener.callListener(["test-done", args]); - } catch (err) { - dump(`Unexpected error: ${err} :: ${err.stack}\n`); - throw err; - } - }); - } - }, - } - ); -}); - -add_task(async function test_api_event_eventListener_result_rejected() { - await runExtensionAPITest( - "extension event eventListener throws (mozIExtensionCallback.call)", - { - backgroundScript({ testAsserts, testLog }) { - const api = browser.mockExtensionAPI; - let listener; - - return new Promise((resolve, reject) => { - testLog("addListener and wait for event to be fired"); - listener = (msg, arg1) => { - if (msg === "test-done") { - testLog(`Resolving result: ${JSON.stringify(arg1)}`); - resolve(arg1); - return; - } - throw new Error("FAKE eventListener exception"); - }; - api.onTestEvent.addListener(listener); - }); - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual( - testResult, - { - isPromise: true, - rejectIsError: true, - errorMessage: "FAKE eventListener exception", - }, - "Got the expected rejected promise" - ); - }, - mockAPIRequestHandler(policy, request) { - if (!request.eventListener) { - throw new Error( - "Unexpected Error: missing ExtensionAPIRequest.eventListener" - ); - } - - if (request.requestType === "addListener") { - Promise.resolve().then(async () => { - const promiseResult = request.eventListener.callListener([]); - const isPromise = promiseResult instanceof Promise; - const err = await promiseResult.catch(e => e); - const rejectIsError = err instanceof Error; - request.eventListener.callListener([ - "test-done", - { isPromise, rejectIsError, errorMessage: err?.message }, - ]); - }); - } - }, - } - ); -}); - -add_task(async function test_api_event_eventListener_throws_on_call() { - await runExtensionAPITest( - "extension event eventListener throws (mozIExtensionCallback.call)", - { - backgroundScript({ testAsserts, testLog }) { - const api = browser.mockExtensionAPI; - let listener; - - return new Promise(resolve => { - testLog("addListener and wait for event to be fired"); - listener = (msg, arg1) => { - if (msg === "test-done") { - testLog(`Resolving result: ${JSON.stringify(arg1)}`); - resolve(); - return; - } - throw new Error("FAKE eventListener exception"); - }; - api.onTestEvent.addListener(listener); - }); - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - }, - mockAPIRequestHandler(policy, request) { - if (!request.eventListener) { - throw new Error( - "Unexpected Error: missing ExtensionAPIRequest.eventListener" - ); - } - - if (request.requestType === "addListener") { - Promise.resolve().then(async () => { - request.eventListener.callListener([]); - request.eventListener.callListener(["test-done"]); - }); - } - }, - } - ); -}); - -add_task(async function test_send_response_eventListener() { - await runExtensionAPITest( - "extension event eventListener sendResponse eventListener argument", - { - backgroundScript({ testAsserts, testLog }) { - const api = browser.mockExtensionAPI; - let listener; - - return new Promise(resolve => { - testLog("addListener and wait for event to be fired"); - listener = (msg, sendResponse) => { - if (msg === "call-sendResponse") { - // eslint-disable-next-line mozilla/no-arbitrary-setTimeout - setTimeout(() => sendResponse("sendResponse-value"), 20); - return true; - } - - resolve(msg); - }; - api.onTestEvent.addListener(listener); - }); - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.equal(testResult, "sendResponse-value", "Got expected value"); - }, - mockAPIRequestHandler(policy, request) { - if (!request.eventListener) { - throw new Error( - "Unexpected Error: missing ExtensionAPIRequest.eventListener" - ); - } - - if (request.requestType === "addListener") { - Promise.resolve().then(async () => { - const res = await request.eventListener.callListener( - ["call-sendResponse"], - { - callbackType: - Ci.mozIExtensionListenerCallOptions.CALLBACK_SEND_RESPONSE, - } - ); - request.eventListener.callListener([res]); - }); - } - }, - } - ); -}); - -add_task(async function test_send_response_multiple_eventListener() { - await runExtensionAPITest("multiple extension event eventListeners", { - backgroundScript({ testAsserts, testLog }) { - const api = browser.mockExtensionAPI; - let listenerNoReply; - let listenerSendResponseReply; - - return new Promise(resolve => { - testLog("addListener and wait for event to be fired"); - listenerNoReply = (msg, sendResponse) => { - return false; - }; - listenerSendResponseReply = (msg, sendResponse) => { - if (msg === "call-sendResponse") { - // eslint-disable-next-line mozilla/no-arbitrary-setTimeout - setTimeout(() => sendResponse("sendResponse-value"), 20); - return true; - } - - resolve(msg); - }; - api.onTestEvent.addListener(listenerNoReply); - api.onTestEvent.addListener(listenerSendResponseReply); - }); - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.equal(testResult, "sendResponse-value", "Got expected value"); - }, - mockAPIRequestHandler(policy, request) { - if (!request.eventListener) { - throw new Error( - "Unexpected Error: missing ExtensionAPIRequest.eventListener" - ); - } - - if (request.requestType === "addListener") { - this._listeners = this._listeners || []; - this._listeners.push(request.eventListener); - if (this._listeners.length === 2) { - Promise.resolve().then(async () => { - const { _listeners } = this; - this._listeners = undefined; - - // Reference to the listener to which we should send the - // final message to complete the test. - const replyListener = _listeners[1]; - - const res = await Promise.race( - _listeners.map(l => - l.callListener(["call-sendResponse"], { - callbackType: - Ci.mozIExtensionListenerCallOptions.CALLBACK_SEND_RESPONSE, - }) - ) - ); - replyListener.callListener([res]); - }); - } - } - }, - }); -}); diff --git a/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_runtime_port.js b/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_runtime_port.js deleted file mode 100644 index 345d9bd0c94c..000000000000 --- a/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_runtime_port.js +++ /dev/null @@ -1,204 +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" - ); -}); - -add_task(async function test_method_return_runtime_port() { - await runExtensionAPITest("API method returns an ExtensionPort instance", { - backgroundScript({ testAsserts, testLog }) { - try { - browser.mockExtensionAPI.methodReturnsPort("port-create-error"); - throw new Error("methodReturnsPort should have raised an exception"); - } catch (err) { - testAsserts.equal( - err?.message, - "An unexpected error occurred", - "Got the expected error" - ); - } - const port = browser.mockExtensionAPI.methodReturnsPort( - "port-create-success" - ); - testAsserts.equal(!!port, true, "Got a port"); - testAsserts.equal( - typeof port.name, - "string", - "port.name should be a string" - ); - testAsserts.equal( - typeof port.sender, - "object", - "port.sender should be an object" - ); - testAsserts.equal( - typeof port.disconnect, - "function", - "port.disconnect method" - ); - testAsserts.equal( - typeof port.postMessage, - "function", - "port.postMessage method" - ); - testAsserts.equal( - typeof port.onDisconnect?.addListener, - "function", - "port.onDisconnect.addListener method" - ); - testAsserts.equal( - typeof port.onMessage?.addListener, - "function", - "port.onDisconnect.addListener method" - ); - return new Promise(resolve => { - let messages = []; - port.onDisconnect.addListener(() => resolve(messages)); - port.onMessage.addListener((...args) => { - messages.push(args); - }); - }); - }, - assertResults({ testError, testResult }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - Assert.deepEqual( - testResult, - [ - [1, 2], - [3, 4], - [5, 6], - ], - "Got the expected results" - ); - }, - mockAPIRequestHandler(policy, request) { - if (request.apiName == "methodReturnsPort") { - if (request.args[0] == "port-create-error") { - return { - type: Ci.mozIExtensionAPIRequestResult.RESULT_VALUE, - value: "not-a-valid-port", - }; - } - return { - type: Ci.mozIExtensionAPIRequestResult.RETURN_VALUE, - value: { - portId: "port-id-1", - name: "a-port-name", - }, - }; - } else if (request.requestType == "addListener") { - if (request.apiObjectType !== "Port") { - throw new Error(`Unexpected objectType ${request}`); - } - - switch (request.apiName) { - case "onDisconnect": - this._onDisconnectCb = request.eventListener; - return; - case "onMessage": - Promise.resolve().then(async () => { - await request.eventListener.callListener([1, 2]); - await request.eventListener.callListener([3, 4]); - await request.eventListener.callListener([5, 6]); - this._onDisconnectCb.callListener([]); - }); - return; - } - } - - throw new Error(`Unexpected request: ${request}`); - }, - }); -}); - -add_task(async function test_port_as_event_listener_eventListener_param() { - await runExtensionAPITest( - "API event eventListener received an ExtensionPort parameter", - { - backgroundScript({ testAsserts, testLog }) { - const api = browser.mockExtensionAPI; - let listener; - - return new Promise((resolve, reject) => { - testLog("addListener and wait for event to be fired"); - listener = port => { - try { - testAsserts.equal(!!port, true, "Got a port parameter"); - testAsserts.equal( - port.name, - "a-port-name-2", - "Got expected port.name value" - ); - testAsserts.equal( - typeof port.disconnect, - "function", - "port.disconnect method" - ); - testAsserts.equal( - typeof port.postMessage, - "function", - "port.disconnect method" - ); - port.onMessage.addListener(msg => { - if (msg === "test-done") { - testLog("Got a port.onMessage event"); - resolve(); - } else { - reject( - new Error( - `port.onMessage got an unexpected message: ${msg}` - ) - ); - } - }); - } catch (err) { - reject(err); - } - }; - api.onTestEvent.addListener(listener); - }); - }, - assertResults({ testError }) { - Assert.deepEqual(testError, null, "Got no error as expected"); - }, - mockAPIRequestHandler(policy, request) { - if ( - request.requestType == "addListener" && - request.apiName == "onTestEvent" - ) { - request.eventListener.callListener([], { - apiObjectType: Ci.mozIExtensionListenerCallOptions.RUNTIME_PORT, - apiObjectDescriptor: { portId: "port-id-2", name: "a-port-name-2" }, - }); - return; - } else if ( - request.requestType == "addListener" && - request.apiObjectType == "Port" && - request.apiObjectId == "port-id-2" - ) { - request.eventListener.callListener(["test-done"]); - return; - } - - throw new Error(`Unexpected request: ${request}`); - }, - } - ); -}); diff --git a/toolkit/components/extensions/test/xpcshell/webidl-api/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/webidl-api/xpcshell.ini deleted file mode 100644 index 4f606c5ddd41..000000000000 --- a/toolkit/components/extensions/test/xpcshell/webidl-api/xpcshell.ini +++ /dev/null @@ -1,29 +0,0 @@ -[DEFAULT] -head = ../head.js ../head_remote.js head_webidl_api.js -firefox-appdir = browser -tags = webextensions webextensions-webidl-api - -prefs = - # Enable support for the extension background service worker. - extensions.backgroundServiceWorker.enabled=true - # Enable Extensions API WebIDL bindings for extension windows. - extensions.webidl-api.enabled=true - # Enable ExtensionMockAPI WebIDL bindings used for unit tests - # related to the API request forwarding and not tied to a particular - # extension API. - extensions.webidl-api.expose_mock_interface=true - # services.settings.server/default_bucket: - # Make sure that loading the default settings for url-classifier-skip-urls - # doesn't interfere with running our tests while IDB operations are in - # flight by overriding the default remote settings bucket pref name to - # ensure that the IDB database isn't created in the first place. - services.settings.server=http://localhost:7777/remote-settings-dummy/v1 - services.settings.default_bucket=nonexistent-bucket-foo - -# NOTE: these tests seems to be timing out because it takes too much time to -# run all tests and then fully exiting the test. -skip-if = os == "android" && verify - -[test_ext_webidl_api.js] -[test_ext_webidl_api_event_callback.js] -[test_ext_webidl_runtime_port.js] diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIAddRemoveListener.h b/toolkit/components/extensions/webidl-api/ExtensionAPIAddRemoveListener.h deleted file mode 100644 index 5020641e233c..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPIAddRemoveListener.h +++ /dev/null @@ -1,36 +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_ExtensionAPIAddRemoveListener_h -#define mozilla_extensions_ExtensionAPIAddRemoveListener_h - -#include "ExtensionAPIRequestForwarder.h" - -namespace mozilla { -namespace extensions { - -class ExtensionAPIAddRemoveListener : public ExtensionAPIRequestForwarder { - public: - enum class EType { - eAddListener, - eRemoveListener, - }; - - ExtensionAPIAddRemoveListener(const EType type, - const nsAString& aApiNamespace, - const nsAString& aApiEvent, - const nsAString& aApiObjectType, - const nsAString& aApiObjectId) - : ExtensionAPIRequestForwarder( - type == EType::eAddListener ? APIRequestType::ADD_LISTENER - : APIRequestType::REMOVE_LISTENER, - aApiNamespace, aApiEvent, aApiObjectType, aApiObjectId) {} -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionAPIAddRemoveListener_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIBase.cpp b/toolkit/components/extensions/webidl-api/ExtensionAPIBase.cpp deleted file mode 100644 index 00e831376404..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPIBase.cpp +++ /dev/null @@ -1,222 +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 "ExtensionAPIBase.h" - -#include "ExtensionAPIRequestForwarder.h" -#include "ExtensionAPIAddRemoveListener.h" -#include "ExtensionAPICallAsyncFunction.h" -#include "ExtensionAPICallFunctionNoReturn.h" -#include "ExtensionAPICallSyncFunction.h" -#include "ExtensionAPIGetProperty.h" -#include "ExtensionEventManager.h" - -#include "mozilla/dom/Promise.h" -#include "mozilla/dom/SerializedStackHolder.h" -#include "mozilla/dom/FunctionBinding.h" - -namespace mozilla { -namespace extensions { - -// ChromeCompatCallbackHandler - -NS_IMPL_ISUPPORTS0(ChromeCompatCallbackHandler) - -// static -void ChromeCompatCallbackHandler::Create( - dom::Promise* aPromise, const RefPtr& aCallback) { - MOZ_ASSERT(aPromise); - MOZ_ASSERT(aCallback); - - RefPtr handler = - new ChromeCompatCallbackHandler(aCallback); - - aPromise->AppendNativeHandler(handler); -} - -void ChromeCompatCallbackHandler::ResolvedCallback( - JSContext* aCx, JS::Handle aValue) { - JS::RootedValue retval(aCx); - IgnoredErrorResult rv; - MOZ_KnownLive(mCallback)->Call({aValue}, &retval, rv); -} - -void ChromeCompatCallbackHandler::RejectedCallback( - JSContext* aCx, JS::Handle aValue) { - JS::RootedValue retval(aCx); - IgnoredErrorResult rv; - // 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. - MOZ_KnownLive(mCallback)->Call({}, &retval, rv); -} - -// WebExtensionStub methods shared between multiple API namespaces. - -void ExtensionAPIBase::CallWebExtMethodNotImplementedNoReturn( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, ErrorResult& aRv) { - aRv.ThrowNotSupportedError("Not implemented"); -} - -void ExtensionAPIBase::CallWebExtMethodNotImplementedAsync( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, - const dom::Optional>& aCallback, - JS::MutableHandle aRetval, ErrorResult& aRv) { - CallWebExtMethodNotImplementedNoReturn(aCx, aApiMethod, aArgs, aRv); -} - -void ExtensionAPIBase::CallWebExtMethodNotImplemented( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, JS::MutableHandle aRetval, - ErrorResult& aRv) { - CallWebExtMethodNotImplementedNoReturn(aCx, aApiMethod, aArgs, aRv); -} - -void ExtensionAPIBase::CallWebExtMethodNoReturn( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, ErrorResult& aRv) { - auto request = CallFunctionNoReturn(aApiMethod); - request->Run(GetGlobalObject(), aCx, aArgs, aRv); - if (aRv.Failed()) { - return; - } -} - -void ExtensionAPIBase::CallWebExtMethod(JSContext* aCx, - const nsAString& aApiMethod, - const dom::Sequence& aArgs, - JS::MutableHandle aRetVal, - ErrorResult& aRv) { - auto request = CallSyncFunction(aApiMethod); - request->Run(GetGlobalObject(), aCx, aArgs, aRetVal, aRv); - if (aRv.Failed()) { - return; - } -} - -void ExtensionAPIBase::CallWebExtMethodAsyncInternal( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, - const RefPtr& aCallback, - JS::MutableHandle aRetval, ErrorResult& aRv) { - auto* global = GetGlobalObject(); - - IgnoredErrorResult erv; - RefPtr domPromise = dom::Promise::Create(global, erv); - if (NS_WARN_IF(erv.Failed())) { - ThrowUnexpectedError(aCx, aRv); - return; - } - MOZ_ASSERT(domPromise); - auto request = CallAsyncFunction(aApiMethod); - request->Run(global, aCx, aArgs, domPromise, aRv); - if (aRv.Failed()) { - return; - } - - // The async method has been called with the chrome-compatible callback - // convention. - if (aCallback) { - ChromeCompatCallbackHandler::Create(domPromise, aCallback); - return; - } - - if (NS_WARN_IF(!ToJSValue(aCx, domPromise, aRetval))) { - ThrowUnexpectedError(aCx, aRv); - return; - } -} - -void ExtensionAPIBase::CallWebExtMethodAsync( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, - const dom::Optional>& aCallback, - JS::MutableHandle aRetval, ErrorResult& aRv) { - RefPtr callback = nullptr; - if (aCallback.WasPassed()) { - callback = &aCallback.Value(); - } - CallWebExtMethodAsyncInternal(aCx, aApiMethod, aArgs, callback, aRetval, aRv); -} - -void ExtensionAPIBase::CallWebExtMethodAsyncAmbiguous( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, JS::MutableHandle aRetval, - ErrorResult& aRv) { - RefPtr chromeCompatCb; - auto lastElement = - aArgs.IsEmpty() ? JS::UndefinedValue() : aArgs.LastElement(); - dom::Sequence callArgs(aArgs); - if (lastElement.isObject() && JS::IsCallable(&lastElement.toObject())) { - JS::Rooted tempRoot(aCx, &lastElement.toObject()); - JS::Rooted tempGlobalRoot(aCx, JS::CurrentGlobalOrNull(aCx)); - chromeCompatCb = new dom::Function(aCx, tempRoot, tempGlobalRoot, - dom::GetIncumbentGlobal()); - - Unused << callArgs.PopLastElement(); - } - CallWebExtMethodAsyncInternal(aCx, aApiMethod, callArgs, chromeCompatCb, - aRetval, aRv); -} - -// ExtensionAPIBase - API Request helpers - -already_AddRefed ExtensionAPIBase::CreateEventManager( - const nsAString& aEventName) { - RefPtr eventMgr = new ExtensionEventManager( - GetGlobalObject(), GetAPINamespace(), aEventName, GetAPIObjectType(), - GetAPIObjectId()); - return eventMgr.forget(); -} - -RefPtr ExtensionAPIBase::CallFunctionNoReturn( - const nsAString& aApiMethod) { - return new ExtensionAPICallFunctionNoReturn( - GetAPINamespace(), aApiMethod, GetAPIObjectType(), GetAPIObjectId()); -} - -RefPtr ExtensionAPIBase::CallSyncFunction( - const nsAString& aApiMethod) { - return new ExtensionAPICallSyncFunction(GetAPINamespace(), aApiMethod, - GetAPIObjectType(), GetAPIObjectId()); -} - -RefPtr ExtensionAPIBase::CallAsyncFunction( - const nsAString& aApiMethod) { - return new ExtensionAPICallAsyncFunction( - GetAPINamespace(), aApiMethod, GetAPIObjectType(), GetAPIObjectId()); -} - -RefPtr ExtensionAPIBase::GetProperty( - const nsAString& aApiProperty) { - return new ExtensionAPIGetProperty(GetAPINamespace(), aApiProperty, - GetAPIObjectType(), GetAPIObjectId()); -} - -RefPtr ExtensionAPIBase::SendAddListener( - const nsAString& aEventName) { - using EType = ExtensionAPIAddRemoveListener::EType; - return new ExtensionAPIAddRemoveListener( - EType::eAddListener, GetAPINamespace(), aEventName, GetAPIObjectType(), - GetAPIObjectId()); -} - -RefPtr ExtensionAPIBase::SendRemoveListener( - const nsAString& aEventName) { - using EType = ExtensionAPIAddRemoveListener::EType; - return new ExtensionAPIAddRemoveListener( - EType::eRemoveListener, GetAPINamespace(), aEventName, GetAPIObjectType(), - GetAPIObjectId()); -} - -// static -void ExtensionAPIBase::ThrowUnexpectedError(JSContext* aCx, ErrorResult& aRv) { - ExtensionAPIRequestForwarder::ThrowUnexpectedError(aCx, aRv); -} - -} // namespace extensions -} // namespace mozilla diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIBase.h b/toolkit/components/extensions/webidl-api/ExtensionAPIBase.h deleted file mode 100644 index 2674cb3d0fab..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPIBase.h +++ /dev/null @@ -1,141 +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_ExtensionAPIBase_h -#define mozilla_extensions_ExtensionAPIBase_h - -#include "mozilla/dom/BindingDeclarations.h" -#include "mozilla/dom/PromiseNativeHandler.h" -#include "mozilla/ErrorResult.h" - -class nsIGlobalObject; - -namespace mozilla { - -namespace dom { -class Function; -} - -namespace extensions { - -class ExtensionAPIAddRemoveListener; -class ExtensionAPICallFunctionNoReturn; -class ExtensionAPICallSyncFunction; -class ExtensionAPICallAsyncFunction; -class ExtensionAPIGetProperty; -class ExtensionEventManager; - -class ExtensionAPIBase { - protected: - virtual nsIGlobalObject* GetGlobalObject() const = 0; - virtual nsString GetAPINamespace() const = 0; - virtual nsString GetAPIObjectType() const = 0; - virtual nsString GetAPIObjectId() const = 0; - - private: - void CallWebExtMethodAsyncInternal(JSContext* aCx, - const nsAString& aApiMethod, - const dom::Sequence& aArgs, - const RefPtr& aCallback, - JS::MutableHandle aRetval, - ErrorResult& aRv); - - public: - // WebExtensionStub methods shared between multiple API namespaces. - - virtual void CallWebExtMethodNotImplementedNoReturn( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, ErrorResult& aRv); - - virtual void CallWebExtMethodNotImplementedAsync( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, - const dom::Optional>& aCallback, - JS::MutableHandle aRetval, ErrorResult& aRv); - - virtual void CallWebExtMethodNotImplemented( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, - JS::MutableHandle aRetval, ErrorResult& aRv); - - virtual void CallWebExtMethodNoReturn(JSContext* aCx, - const nsAString& aApiMethod, - const dom::Sequence& aArgs, - ErrorResult& aRv); - virtual void CallWebExtMethod(JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, - JS::MutableHandle aRetVal, - ErrorResult& aRv); - - virtual void CallWebExtMethodAsync( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, - const dom::Optional>& aCallback, - JS::MutableHandle aRetVal, ErrorResult& aRv); - - virtual void CallWebExtMethodAsyncAmbiguous( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, - JS::MutableHandle aRetVal, ErrorResult& aRv); - - // API Requests helpers. - already_AddRefed CreateEventManager( - const nsAString& aEventName); - - RefPtr CallFunctionNoReturn( - const nsAString& aApiMethod); - - RefPtr CallSyncFunction( - const nsAString& aApiMethod); - - RefPtr CallAsyncFunction( - const nsAString& aApiMethod); - - RefPtr GetProperty(const nsAString& aApiProperty); - - RefPtr SendAddListener( - const nsAString& aEventName); - - RefPtr SendRemoveListener( - const nsAString& aEventName); - - static void ThrowUnexpectedError(JSContext* aCx, ErrorResult& aRv); -}; - -class ExtensionAPINamespace : public ExtensionAPIBase { - protected: - nsString GetAPIObjectType() const override { return VoidString(); } - - nsString GetAPIObjectId() const override { return VoidString(); }; -}; - -class ChromeCompatCallbackHandler final : public dom::PromiseNativeHandler { - public: - NS_DECL_THREADSAFE_ISUPPORTS - - static void Create(dom::Promise* aPromise, - const RefPtr& aCallback); - - MOZ_CAN_RUN_SCRIPT void ResolvedCallback( - JSContext* aCx, JS::Handle aValue) override; - MOZ_CAN_RUN_SCRIPT void RejectedCallback( - JSContext* aCx, JS::Handle aValue) override; - - private: - explicit ChromeCompatCallbackHandler(const RefPtr& aCallback) - : mCallback(aCallback) { - MOZ_ASSERT(aCallback); - } - - ~ChromeCompatCallbackHandler() = default; - - RefPtr mCallback; -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionAPIBase_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPICallAsyncFunction.h b/toolkit/components/extensions/webidl-api/ExtensionAPICallAsyncFunction.h deleted file mode 100644 index bf2f57ceb399..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPICallAsyncFunction.h +++ /dev/null @@ -1,29 +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_ExtensionAPICallAsyncFunction_h -#define mozilla_extensions_ExtensionAPICallAsyncFunction_h - -#include "ExtensionAPIRequestForwarder.h" - -namespace mozilla { -namespace extensions { - -class ExtensionAPICallAsyncFunction : public ExtensionAPIRequestForwarder { - public: - ExtensionAPICallAsyncFunction(const nsAString& aApiNamespace, - const nsAString& aApiMethod, - const nsAString& aApiObjectType = u""_ns, - const nsAString& aApiObjectId = u""_ns) - : ExtensionAPIRequestForwarder( - mozIExtensionAPIRequest::RequestType::CALL_FUNCTION_ASYNC, - aApiNamespace, aApiMethod, aApiObjectType, aApiObjectId) {} -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionAPICallAsyncFunction_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPICallFunctionNoReturn.h b/toolkit/components/extensions/webidl-api/ExtensionAPICallFunctionNoReturn.h deleted file mode 100644 index 4ff179f6520f..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPICallFunctionNoReturn.h +++ /dev/null @@ -1,29 +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_ExtensionAPICallFunctionNoReturn_h -#define mozilla_extensions_ExtensionAPICallFunctionNoReturn_h - -#include "ExtensionAPIRequestForwarder.h" - -namespace mozilla { -namespace extensions { - -class ExtensionAPICallFunctionNoReturn : public ExtensionAPIRequestForwarder { - public: - ExtensionAPICallFunctionNoReturn(const nsAString& aApiNamespace, - const nsAString& aApiMethod, - const nsAString& aApiObjectType = u""_ns, - const nsAString& aApiObjectId = u""_ns) - : ExtensionAPIRequestForwarder( - mozIExtensionAPIRequest::RequestType::CALL_FUNCTION_NO_RETURN, - aApiNamespace, aApiMethod, aApiObjectType, aApiObjectId) {} -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionAPICallFunctionNoReturn_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPICallSyncFunction.h b/toolkit/components/extensions/webidl-api/ExtensionAPICallSyncFunction.h deleted file mode 100644 index 2a5808251471..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPICallSyncFunction.h +++ /dev/null @@ -1,29 +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_ExtensionAPICallSyncFunction_h -#define mozilla_extensions_ExtensionAPICallSyncFunction_h - -#include "ExtensionAPIRequestForwarder.h" - -namespace mozilla { -namespace extensions { - -class ExtensionAPICallSyncFunction : public ExtensionAPIRequestForwarder { - public: - ExtensionAPICallSyncFunction(const nsAString& aApiNamespace, - const nsAString& aApiMethod, - const nsAString& aApiObjectType = u""_ns, - const nsAString& aApiObjectId = u""_ns) - : ExtensionAPIRequestForwarder( - mozIExtensionAPIRequest::RequestType::CALL_FUNCTION, aApiNamespace, - aApiMethod, aApiObjectType, aApiObjectId) {} -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionAPICallSyncFunction_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIGetProperty.h b/toolkit/components/extensions/webidl-api/ExtensionAPIGetProperty.h deleted file mode 100644 index 30b9423dad85..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPIGetProperty.h +++ /dev/null @@ -1,29 +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_ExtensionAPIGetProperty_h -#define mozilla_extensions_ExtensionAPIGetProperty_h - -#include "ExtensionAPIRequestForwarder.h" - -namespace mozilla { -namespace extensions { - -class ExtensionAPIGetProperty : public ExtensionAPIRequestForwarder { - public: - ExtensionAPIGetProperty(const nsAString& aApiNamespace, - const nsAString& aApiProperty, - const nsAString& aApiObjectType = u""_ns, - const nsAString& aApiObjectId = u""_ns) - : ExtensionAPIRequestForwarder( - mozIExtensionAPIRequest::RequestType::GET_PROPERTY, aApiNamespace, - aApiProperty, aApiObjectType, aApiObjectId) {} -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionAPICallSyncFunction_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIRequest.cpp b/toolkit/components/extensions/webidl-api/ExtensionAPIRequest.cpp deleted file mode 100644 index b17776b33ee1..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPIRequest.cpp +++ /dev/null @@ -1,214 +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 "ExtensionAPIRequest.h" - -#include "mozilla/dom/ClientInfo.h" -#include "mozilla/extensions/WebExtensionPolicy.h" -#include "mozilla/ipc/BackgroundUtils.h" // PrincipalInfoToPrincipal - -namespace mozilla { -namespace extensions { - -// mozIExtensionServiceWorkerInfo - -NS_IMPL_ISUPPORTS(ExtensionServiceWorkerInfo, mozIExtensionServiceWorkerInfo) - -NS_IMETHODIMP -ExtensionServiceWorkerInfo::GetPrincipal(nsIPrincipal** aPrincipal) { - MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_ARG_POINTER(aPrincipal); - auto principalOrErr = PrincipalInfoToPrincipal(mClientInfo.PrincipalInfo()); - if (NS_WARN_IF(principalOrErr.isErr())) { - return NS_ERROR_UNEXPECTED; - } - nsCOMPtr principal = principalOrErr.unwrap(); - principal.forget(aPrincipal); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionServiceWorkerInfo::GetScriptURL(nsAString& aScriptURL) { - MOZ_ASSERT(NS_IsMainThread()); - aScriptURL = NS_ConvertUTF8toUTF16(mClientInfo.URL()); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionServiceWorkerInfo::GetClientInfoId(nsAString& aClientInfoId) { - MOZ_ASSERT(NS_IsMainThread()); - aClientInfoId = NS_ConvertUTF8toUTF16(mClientInfo.Id().ToString()); - return NS_OK; -} - -// mozIExtensionAPIRequest - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionAPIRequest) - NS_INTERFACE_MAP_ENTRY(mozIExtensionAPIRequest) - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTION_CLASS(ExtensionAPIRequest) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionAPIRequest) -NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionAPIRequest) - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ExtensionAPIRequest) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventListener) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSWInfo) -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(mStack) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ExtensionAPIRequest) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventListener) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mSWInfo) - tmp->mStack.setUndefined(); - tmp->mArgs.setUndefined(); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -ExtensionAPIRequest::ExtensionAPIRequest( - const mozIExtensionAPIRequest::RequestType aRequestType, - const ExtensionAPIRequestTarget& aRequestTarget) { - MOZ_ASSERT(NS_IsMainThread()); - mRequestType = aRequestType; - mRequestTarget = aRequestTarget; - mozilla::HoldJSObjects(this); -} - -void ExtensionAPIRequest::Init(Maybe& aSWClientInfo, - JS::HandleValue aRequestArgs, - JS::HandleValue aCallerStack) { - MOZ_ASSERT(NS_IsMainThread()); - mSWClientInfo = aSWClientInfo; - mArgs.set(aRequestArgs); - mStack.set(aCallerStack); -} - -NS_IMETHODIMP -ExtensionAPIRequest::ToString(nsACString& aResult) { - aResult.Truncate(); - - nsAutoCString requestType; - nsAutoCString apiNamespace; - nsAutoCString apiName; - GetRequestType(requestType); - GetApiNamespace(apiNamespace); - GetApiName(apiName); - - if (mRequestTarget.mObjectType.IsEmpty()) { - aResult.AppendPrintf("[ExtensionAPIRequest %s %s.%s]", requestType.get(), - apiNamespace.get(), apiName.get()); - } else { - nsAutoCString objectType; - nsAutoCString objectId; - GetApiObjectType(objectType); - GetApiObjectId(objectId); - - aResult.AppendPrintf("[ExtensionAPIRequest %s %s.%s.%s (%s)]", - requestType.get(), apiNamespace.get(), - objectType.get(), apiName.get(), objectId.get()); - } - - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetRequestType(nsACString& aRequestTypeName) { - MOZ_ASSERT(NS_IsMainThread()); - switch (mRequestType) { - case mozIExtensionAPIRequest::RequestType::CALL_FUNCTION: - aRequestTypeName = "callFunction"_ns; - break; - case mozIExtensionAPIRequest::RequestType::CALL_FUNCTION_NO_RETURN: - aRequestTypeName = "callFunctionNoReturn"_ns; - break; - case mozIExtensionAPIRequest::RequestType::CALL_FUNCTION_ASYNC: - aRequestTypeName = "callAsyncFunction"_ns; - break; - case mozIExtensionAPIRequest::RequestType::ADD_LISTENER: - aRequestTypeName = "addListener"_ns; - break; - case mozIExtensionAPIRequest::RequestType::REMOVE_LISTENER: - aRequestTypeName = "removeListener"_ns; - break; - case mozIExtensionAPIRequest::RequestType::GET_PROPERTY: - aRequestTypeName = "getProperty"_ns; - break; - default: - return NS_ERROR_UNEXPECTED; - } - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetApiNamespace(nsACString& aApiNamespace) { - MOZ_ASSERT(NS_IsMainThread()); - aApiNamespace.Assign(NS_ConvertUTF16toUTF8(mRequestTarget.mNamespace)); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetApiName(nsACString& aApiName) { - MOZ_ASSERT(NS_IsMainThread()); - aApiName.Assign(NS_ConvertUTF16toUTF8(mRequestTarget.mMethod)); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetApiObjectType(nsACString& aApiObjectType) { - MOZ_ASSERT(NS_IsMainThread()); - aApiObjectType.Assign(NS_ConvertUTF16toUTF8(mRequestTarget.mObjectType)); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetApiObjectId(nsACString& aApiObjectId) { - MOZ_ASSERT(NS_IsMainThread()); - aApiObjectId.Assign(NS_ConvertUTF16toUTF8(mRequestTarget.mObjectId)); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetArgs(JSContext* aCx, - JS::MutableHandle aRetval) { - MOZ_ASSERT(NS_IsMainThread()); - aRetval.set(mArgs); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetCallerSavedFrame( - JSContext* aCx, JS::MutableHandle aSavedFrame) { - MOZ_ASSERT(NS_IsMainThread()); - aSavedFrame.set(mStack); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetServiceWorkerInfo( - mozIExtensionServiceWorkerInfo** aSWInfo) { - MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_ARG_POINTER(aSWInfo); - if (mSWClientInfo.isSome() && !mSWInfo) { - mSWInfo = new ExtensionServiceWorkerInfo(*mSWClientInfo); - } - NS_IF_ADDREF(*aSWInfo = mSWInfo); - return NS_OK; -} - -NS_IMETHODIMP -ExtensionAPIRequest::GetEventListener(mozIExtensionEventListener** aListener) { - MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_ARG_POINTER(aListener); - NS_IF_ADDREF(*aListener = mEventListener); - return NS_OK; -} - -} // namespace extensions -} // namespace mozilla diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIRequest.h b/toolkit/components/extensions/webidl-api/ExtensionAPIRequest.h deleted file mode 100644 index c2355372b71b..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPIRequest.h +++ /dev/null @@ -1,115 +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_ExtensionAPIRequest_h -#define mozilla_extensions_ExtensionAPIRequest_h - -#include "ExtensionEventListener.h" - -#include "mozIExtensionAPIRequestHandling.h" -#include "mozilla/HoldDropJSObjects.h" -#include "mozilla/dom/ClientInfo.h" -#include "mozilla/extensions/WebExtensionPolicy.h" -#include "nsCycleCollectionParticipant.h" - -namespace mozilla { -namespace extensions { - -class ExtensionAPIRequestForwarder; -class RequestWorkerRunnable; - -// Represent the target of the API request forwarded, mObjectType and mObjectId -// are only expected to be polulated when the API request is originated from API -// object (like an ExtensionPort returned by a call to browser.runtime.connect). -struct ExtensionAPIRequestTarget { - nsString mNamespace; - nsString mMethod; - nsString mObjectType; - nsString mObjectId; -}; - -// A class that represents the service worker that has originated the API -// request. -class ExtensionServiceWorkerInfo : public mozIExtensionServiceWorkerInfo { - public: - NS_DECL_MOZIEXTENSIONSERVICEWORKERINFO - NS_DECL_ISUPPORTS - - explicit ExtensionServiceWorkerInfo(const dom::ClientInfo& aClientInfo) - : mClientInfo(aClientInfo) {} - - private: - virtual ~ExtensionServiceWorkerInfo() = default; - - dom::ClientInfo mClientInfo; -}; - -// A class that represents a WebExtensions API request (a method call, -// add/remote listener or accessing a property getter) forwarded by the -// WebIDL bindings to the mozIExtensionAPIRequestHandler. -class ExtensionAPIRequest : public mozIExtensionAPIRequest { - public: - using APIRequestType = mozIExtensionAPIRequest::RequestType; - - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionAPIRequest) - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_MOZIEXTENSIONAPIREQUEST - - explicit ExtensionAPIRequest( - const mozIExtensionAPIRequest::RequestType aRequestType, - const ExtensionAPIRequestTarget& aRequestTarget); - - void Init(Maybe& aSWClientInfo, JS::HandleValue aRequestArgs, - JS::HandleValue aCallerStack); - - static bool ShouldHaveResult(const APIRequestType& aRequestType) { - switch (aRequestType) { - case APIRequestType::GET_PROPERTY: - case APIRequestType::CALL_FUNCTION: - case APIRequestType::CALL_FUNCTION_ASYNC: - return true; - case APIRequestType::CALL_FUNCTION_NO_RETURN: - case APIRequestType::ADD_LISTENER: - case APIRequestType::REMOVE_LISTENER: - break; - default: - MOZ_DIAGNOSTIC_ASSERT(false, "Unexpected APIRequestType"); - } - - return false; - } - - bool ShouldHaveResult() const { return ShouldHaveResult(mRequestType); } - - void SetEventListener(const RefPtr& aListener) { - MOZ_ASSERT(!mEventListener); - mEventListener = aListener; - } - - private: - virtual ~ExtensionAPIRequest() { - mSWClientInfo = Nothing(); - mArgs.setUndefined(); - mStack.setUndefined(); - mEventListener = nullptr; - mozilla::DropJSObjects(this); - }; - - APIRequestType mRequestType; - ExtensionAPIRequestTarget mRequestTarget; - JS::Heap mStack; - JS::Heap mArgs; - Maybe mSWClientInfo; - RefPtr mSWInfo; - - // Only set for addListener/removeListener API requests. - RefPtr mEventListener; -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionAPIRequest_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.cpp b/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.cpp deleted file mode 100644 index a689b48c16ac..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.cpp +++ /dev/null @@ -1,606 +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 "ExtensionAPIRequestForwarder.h" -#include "ExtensionEventListener.h" - -#include "js/Promise.h" -#include "mozilla/dom/Client.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/dom/ClonedErrorHolder.h" -#include "mozilla/dom/ClonedErrorHolderBinding.h" -#include "mozilla/dom/ExtensionBrowserBinding.h" -#include "mozilla/dom/FunctionBinding.h" -#include "mozilla/dom/WorkerPrivate.h" -#include "mozilla/dom/SerializedStackHolder.h" -#include "mozilla/dom/ServiceWorkerInfo.h" -#include "mozilla/dom/ServiceWorkerManager.h" -#include "mozilla/dom/ServiceWorkerRegistrationInfo.h" -#include "mozilla/dom/StructuredCloneTags.h" -#include "mozilla/ExtensionPolicyService.h" -#include "nsIGlobalObject.h" -#include "nsImportModule.h" -#include "nsIXPConnect.h" - -namespace mozilla { -namespace extensions { - -// ExtensionAPIRequestForwarder - -// static -void ExtensionAPIRequestForwarder::ThrowUnexpectedError(JSContext* aCx, - ErrorResult& aRv) { - aRv.MightThrowJSException(); - JS_ReportErrorASCII(aCx, "An unexpected error occurred"); - aRv.StealExceptionFromJSContext(aCx); -} - -ExtensionAPIRequestForwarder::ExtensionAPIRequestForwarder( - const mozIExtensionAPIRequest::RequestType aRequestType, - const nsAString& aApiNamespace, const nsAString& aApiMethod, - const nsAString& aApiObjectType, const nsAString& aApiObjectId) { - mRequestType = aRequestType; - mRequestTarget.mNamespace = aApiNamespace; - mRequestTarget.mMethod = aApiMethod; - mRequestTarget.mObjectType = aApiObjectType; - mRequestTarget.mObjectId = aApiObjectId; -} - -// static -nsresult ExtensionAPIRequestForwarder::JSArrayToSequence( - JSContext* aCx, JS::HandleValue aJSValue, - dom::Sequence& aResult) { - bool isArray; - JS::Rooted obj(aCx, aJSValue.toObjectOrNull()); - - if (NS_WARN_IF(!obj || !JS::IsArrayObject(aCx, obj, &isArray))) { - return NS_ERROR_UNEXPECTED; - } - - if (isArray) { - uint32_t len; - if (NS_WARN_IF(!JS::GetArrayLength(aCx, obj, &len))) { - return NS_ERROR_UNEXPECTED; - } - - for (uint32_t i = 0; i < len; i++) { - JS::RootedValue v(aCx); - JS_GetElement(aCx, obj, i, &v); - if (NS_WARN_IF(!aResult.AppendElement(v, fallible))) { - return NS_ERROR_OUT_OF_MEMORY; - } - } - } else if (NS_WARN_IF(!aResult.AppendElement(aJSValue, fallible))) { - return NS_ERROR_OUT_OF_MEMORY; - } - - return NS_OK; -} - -/* static */ -mozIExtensionAPIRequestHandler& -ExtensionAPIRequestForwarder::APIRequestHandler() { - static nsCOMPtr sAPIRequestHandler; - - MOZ_ASSERT(NS_IsMainThread()); - - if (MOZ_UNLIKELY(!sAPIRequestHandler)) { - sAPIRequestHandler = - do_ImportModule("resource://gre/modules/ExtensionProcessScript.jsm", - "ExtensionAPIRequestHandler"); - MOZ_RELEASE_ASSERT(sAPIRequestHandler); - ClearOnShutdown(&sAPIRequestHandler); - } - return *sAPIRequestHandler; -} - -void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - ExtensionEventListener* aListener, - JS::MutableHandleValue aRetVal, - ErrorResult& aRv) { - MOZ_ASSERT(dom::IsCurrentThreadRunningWorker()); - - dom::WorkerPrivate* workerPrivate = dom::GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - - RefPtr runnable = - new RequestWorkerRunnable(workerPrivate, this); - - RefPtr domPromise; - - IgnoredErrorResult rv; - - switch (mRequestType) { - case APIRequestType::CALL_FUNCTION_ASYNC: - domPromise = dom::Promise::Create(aGlobal, rv); - if (NS_WARN_IF(rv.Failed())) { - ThrowUnexpectedError(aCx, aRv); - return; - } - - runnable->Init(aGlobal, aCx, aArgs, domPromise, rv); - break; - - case APIRequestType::ADD_LISTENER: - [[fallthrough]]; - case APIRequestType::REMOVE_LISTENER: - runnable->Init(aGlobal, aCx, aArgs, aListener, aRv); - break; - - default: - runnable->Init(aGlobal, aCx, aArgs, rv); - } - - if (NS_WARN_IF(rv.Failed())) { - ThrowUnexpectedError(aCx, aRv); - return; - } - - runnable->Dispatch(dom::WorkerStatus::Canceling, rv); - if (NS_WARN_IF(rv.Failed())) { - ThrowUnexpectedError(aCx, aRv); - return; - } - - auto resultType = runnable->GetResultType(); - if (resultType.isNothing()) { - if (NS_WARN_IF(ExtensionAPIRequest::ShouldHaveResult(mRequestType))) { - ThrowUnexpectedError(aCx, aRv); - } - return; - } - - // Read and throw the extension error if needed. - if (resultType.isSome() && *resultType == APIResultType::EXTENSION_ERROR) { - JS::Rooted ignoredResultValue(aCx); - runnable->ReadResult(aCx, &ignoredResultValue, aRv); - // When the result type is an error aRv is expected to be - // failed, if it is not throw the generic - // "An unexpected error occurred". - if (NS_WARN_IF(!aRv.Failed())) { - ThrowUnexpectedError(aCx, aRv); - } - return; - } - - if (mRequestType == APIRequestType::CALL_FUNCTION_ASYNC) { - MOZ_ASSERT(domPromise); - if (NS_WARN_IF(!ToJSValue(aCx, domPromise, aRetVal))) { - ThrowUnexpectedError(aCx, aRv); - } - return; - } - - JS::Rooted resultValue(aCx); - runnable->ReadResult(aCx, &resultValue, rv); - if (NS_WARN_IF(rv.Failed())) { - ThrowUnexpectedError(aCx, aRv); - return; - } - - aRetVal.set(resultValue); -} - -void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - JS::MutableHandleValue aRetVal, - ErrorResult& aRv) { - Run(aGlobal, aCx, aArgs, nullptr, aRetVal, aRv); -} - -void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - ErrorResult& aRv) { - JS::Rooted ignoredRetval(aCx); - Run(aGlobal, aCx, aArgs, nullptr, &ignoredRetval, aRv); -} - -void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - ExtensionEventListener* aListener, - ErrorResult& aRv) { - MOZ_ASSERT(aListener); - JS::Rooted ignoredRetval(aCx); - Run(aGlobal, aCx, aArgs, aListener, &ignoredRetval, aRv); -} - -void ExtensionAPIRequestForwarder::Run( - nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - const RefPtr& aPromiseRetval, ErrorResult& aRv) { - MOZ_ASSERT(aPromiseRetval); - JS::Rooted promisedRetval(aCx); - Run(aGlobal, aCx, aArgs, &promisedRetval, aRv); - if (aRv.Failed()) { - return; - } - aPromiseRetval->MaybeResolve(promisedRetval); -} - -void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx, - JS::MutableHandleValue aRetVal, - ErrorResult& aRv) { - Run(aGlobal, aCx, {}, aRetVal, aRv); -} - -namespace { - -// Custom PromiseWorkerProxy callback to deserialize error objects -// from ClonedErrorHolder structured clone data. -JSObject* ExtensionAPIRequestStructuredCloneRead( - JSContext* aCx, JSStructuredCloneReader* aReader, - const dom::PromiseWorkerProxy* aProxy, uint32_t aTag, uint32_t aData) { - // Deserialize ClonedErrorHolder that may have been structured cloned - // as a result of a resolved/rejected promise. - if (aTag == dom::SCTAG_DOM_CLONED_ERROR_OBJECT) { - return dom::ClonedErrorHolder::ReadStructuredClone(aCx, aReader, nullptr); - } - - return nullptr; -} - -// Custom PromiseWorkerProxy callback to serialize error objects into -// ClonedErrorHolder structured clone data. -bool ExtensionAPIRequestStructuredCloneWrite(JSContext* aCx, - JSStructuredCloneWriter* aWriter, - dom::PromiseWorkerProxy* aProxy, - JS::HandleObject aObj) { - // Try to serialize the object as a CloneErrorHolder, if it fails then - // the object wasn't an error. - IgnoredErrorResult rv; - RefPtr ceh = - dom::ClonedErrorHolder::Create(aCx, aObj, rv); - if (NS_WARN_IF(rv.Failed()) || !ceh) { - return false; - } - - return ceh->WriteStructuredClone(aCx, aWriter, nullptr); -} - -} // namespace - -RequestWorkerRunnable::RequestWorkerRunnable( - dom::WorkerPrivate* aWorkerPrivate, - ExtensionAPIRequestForwarder* aOuterAPIRequest) - : WorkerMainThreadRunnable(aWorkerPrivate, - "ExtensionAPIRequest :: WorkerRunnable"_ns) { - MOZ_ASSERT(dom::IsCurrentThreadRunningWorker()); - - MOZ_ASSERT(aOuterAPIRequest); - mOuterRequest = aOuterAPIRequest; -} - -void RequestWorkerRunnable::Init(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - ExtensionEventListener* aListener, - ErrorResult& aRv) { - MOZ_ASSERT(dom::IsCurrentThreadRunningWorker()); - - auto* workerScope = mWorkerPrivate->GlobalScope(); - if (NS_WARN_IF(!workerScope)) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return; - } - - mClientInfo = workerScope->GetClientInfo(); - if (mClientInfo.isNothing()) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return; - } - - IgnoredErrorResult rv; - SerializeArgs(aCx, aArgs, rv); - if (NS_WARN_IF(rv.Failed())) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return; - } - - SerializeCallerStack(aCx); - mEventListener = aListener; -} - -void RequestWorkerRunnable::Init(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - const RefPtr& aPromiseRetval, - ErrorResult& aRv) { - // Custom callbacks needed to make the PromiseWorkerProxy instance to - // be able to write and read errors using CloneErrorHolder. - static const dom::PromiseWorkerProxy:: - PromiseWorkerProxyStructuredCloneCallbacks - kExtensionAPIRequestStructuredCloneCallbacks = { - ExtensionAPIRequestStructuredCloneRead, - ExtensionAPIRequestStructuredCloneWrite, - }; - - Init(aGlobal, aCx, aArgs, /* aListener */ nullptr, aRv); - if (aRv.Failed()) { - return; - } - - mPromiseProxy = dom::PromiseWorkerProxy::Create( - mWorkerPrivate, aPromiseRetval, - &kExtensionAPIRequestStructuredCloneCallbacks); -} - -void RequestWorkerRunnable::SerializeCallerStack(JSContext* aCx) { - MOZ_ASSERT(dom::IsCurrentThreadRunningWorker()); - MOZ_ASSERT(mStackHolder.isNothing()); - mStackHolder = Some(dom::GetCurrentStack(aCx)); -} - -void RequestWorkerRunnable::DeserializeCallerStack( - JSContext* aCx, JS::MutableHandleValue aRetval) { - MOZ_ASSERT(NS_IsMainThread()); - if (mStackHolder.isSome()) { - JS::RootedObject savedFrame(aCx, mStackHolder->get()->ReadStack(aCx)); - aRetval.set(JS::ObjectValue(*savedFrame)); - mStackHolder = Nothing(); - } -} - -void RequestWorkerRunnable::SerializeArgs(JSContext* aCx, - const dom::Sequence& aArgs, - ErrorResult& aRv) { - MOZ_ASSERT(dom::IsCurrentThreadRunningWorker()); - MOZ_ASSERT(!mArgsHolder); - - JS::Rooted jsval(aCx); - if (NS_WARN_IF(!ToJSValue(aCx, aArgs, &jsval))) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return; - } - - mArgsHolder = Some(MakeUnique( - dom::StructuredCloneHolder::CloningSupported, - dom::StructuredCloneHolder::TransferringNotSupported, - JS::StructuredCloneScope::SameProcess)); - mArgsHolder->get()->Write(aCx, jsval, aRv); -} - -nsresult RequestWorkerRunnable::DeserializeArgs( - JSContext* aCx, JS::MutableHandle aArgs) { - MOZ_ASSERT(NS_IsMainThread()); - if (mArgsHolder.isSome() && mArgsHolder->get()->HasData()) { - IgnoredErrorResult rv; - - JS::Rooted jsvalue(aCx); - mArgsHolder->get()->Read(xpc::CurrentNativeGlobal(aCx), aCx, &jsvalue, rv); - if (NS_WARN_IF(rv.Failed())) { - return NS_ERROR_UNEXPECTED; - } - - aArgs.set(jsvalue); - } - - return NS_OK; -} - -bool RequestWorkerRunnable::MainThreadRun() { - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr handler = - &ExtensionAPIRequestForwarder::APIRequestHandler(); - nsCOMPtr wrapped = do_QueryInterface(handler); - dom::AutoJSAPI jsapi; - if (!jsapi.Init(wrapped->GetJSObjectGlobal())) { - return false; - } - - auto* cx = jsapi.cx(); - JS::Rooted retval(cx); - return HandleAPIRequest(cx, &retval); -} - -already_AddRefed RequestWorkerRunnable::CreateAPIRequest( - JSContext* aCx) { - JS::Rooted callArgs(aCx); - JS::Rooted callerStackValue(aCx); - - DeserializeArgs(aCx, &callArgs); - DeserializeCallerStack(aCx, &callerStackValue); - - RefPtr request = new ExtensionAPIRequest( - mOuterRequest->GetRequestType(), *mOuterRequest->GetRequestTarget()); - request->Init(mClientInfo, callArgs, callerStackValue); - - if (mEventListener) { - request->SetEventListener(mEventListener.forget()); - } - - return request.forget(); -} - -already_AddRefed -RequestWorkerRunnable::GetWebExtensionPolicy() { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mWorkerPrivate); - auto* baseURI = mWorkerPrivate->GetBaseURI(); - RefPtr policy = - ExtensionPolicyService::GetSingleton().GetByURL(baseURI); - return policy.forget(); -} - -bool RequestWorkerRunnable::HandleAPIRequest(JSContext* aCx, - JS::MutableHandleValue aRetval) { - MOZ_ASSERT(NS_IsMainThread()); - - RefPtr policy = GetWebExtensionPolicy(); - if (NS_WARN_IF(!policy || !policy->Active())) { - // Fails if no extension policy object has been found, or if the - // extension is not active. - return false; - } - - nsresult rv; - - RefPtr request = CreateAPIRequest(aCx); - - nsCOMPtr handler = - &ExtensionAPIRequestForwarder::APIRequestHandler(); - RefPtr apiResult; - rv = handler->HandleAPIRequest(policy, request, getter_AddRefs(apiResult)); - - if (NS_FAILED(rv)) { - return false; - } - - // A missing apiResult is expected for some request types - // (e.g. CALL_FUNCTION_NO_RETURN/ADD_LISTENER/REMOVE_LISTENER). - // If the apiResult is missing for a request type that expects - // to have one, consider the request as failed with an unknown error. - if (!apiResult) { - return !request->ShouldHaveResult(); - } - - mozIExtensionAPIRequestResult::ResultType resultType; - apiResult->GetType(&resultType); - apiResult->GetValue(aRetval); - - mResultType = Some(resultType); - - bool isExtensionError = - resultType == mozIExtensionAPIRequestResult::ResultType::EXTENSION_ERROR; - bool okSerializedError = false; - - if (aRetval.isObject()) { - // Try to serialize the result as an ClonedErrorHolder - // (because all API requests could receive one for EXTENSION_ERROR - // result types, and some also as a RETURN_VALUE result, e.g. - // runtime.lastError). - JS::Rooted errObj(aCx, &aRetval.toObject()); - IgnoredErrorResult rv; - RefPtr ceh = - dom::ClonedErrorHolder::Create(aCx, errObj, rv); - if (!rv.Failed() && ceh) { - JS::RootedObject obj(aCx); - // Note: `ToJSValue` cannot be used because ClonedErrorHolder isn't - // wrapper cached. - okSerializedError = ceh->WrapObject(aCx, nullptr, &obj); - aRetval.setObject(*obj); - } else { - okSerializedError = false; - } - } - - if (isExtensionError && !okSerializedError) { - NS_WARNING("Failed to wrap ClonedErrorHolder"); - MOZ_DIAGNOSTIC_ASSERT(false, "Failed to wrap ClonedErrorHolder"); - return false; - } - - if (isExtensionError && !aRetval.isObject()) { - NS_WARNING("Unexpected non-object error"); - return false; - } - - switch (resultType) { - case mozIExtensionAPIRequestResult::ResultType::RETURN_VALUE: - return ProcessHandlerResult(aCx, aRetval); - case mozIExtensionAPIRequestResult::ResultType::EXTENSION_ERROR: - if (!aRetval.isObject()) { - return false; - } - return ProcessHandlerResult(aCx, aRetval); - } - - MOZ_DIAGNOSTIC_ASSERT(false, "Unexpected API request ResultType"); - return false; -} - -bool RequestWorkerRunnable::ProcessHandlerResult( - JSContext* aCx, JS::MutableHandleValue aRetval) { - MOZ_ASSERT(NS_IsMainThread()); - - if (mOuterRequest->GetRequestType() == APIRequestType::CALL_FUNCTION_ASYNC) { - if (NS_WARN_IF(mResultType.isNothing())) { - return false; - } - - if (*mResultType == APIResultType::RETURN_VALUE) { - // For an Async API method we expect a promise object to be set - // as the value to return, if it is not we return earlier here - // (and then throw a generic unexpected error to the caller). - if (NS_WARN_IF(!aRetval.isObject())) { - return false; - } - JS::Rooted obj(aCx, &aRetval.toObject()); - if (NS_WARN_IF(!JS::IsPromiseObject(obj))) { - return false; - } - - ErrorResult rv; - nsIGlobalObject* glob = xpc::CurrentNativeGlobal(aCx); - already_AddRefed promise = - dom::Promise::Resolve(glob, aCx, aRetval, rv); - if (rv.Failed()) { - return false; - } - promise.take()->AppendNativeHandler(mPromiseProxy); - return true; - } - } - - switch (*mResultType) { - case APIResultType::RETURN_VALUE: - [[fallthrough]]; - case APIResultType::EXTENSION_ERROR: { - // In all other case we expect the result to be: - // - a structured clonable result - // - an extension error (e.g. due to the API call params validation - // errors), - // previously converted into a CloneErrorHolder - IgnoredErrorResult rv; - mResultHolder = Some(MakeUnique( - dom::StructuredCloneHolder::CloningSupported, - dom::StructuredCloneHolder::TransferringNotSupported, - JS::StructuredCloneScope::SameProcess)); - mResultHolder->get()->Write(aCx, aRetval, rv); - return !rv.Failed(); - } - } - - MOZ_DIAGNOSTIC_ASSERT(false, "Unexpected API request ResultType"); - return false; -} - -void RequestWorkerRunnable::ReadResult(JSContext* aCx, - JS::MutableHandleValue aResult, - ErrorResult& aRv) { - MOZ_ASSERT(mWorkerPrivate->IsOnCurrentThread()); - if (mResultHolder.isNothing() || !mResultHolder->get()->HasData()) { - return; - } - - if (NS_WARN_IF(mResultType.isNothing())) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return; - } - - switch (*mResultType) { - case mozIExtensionAPIRequestResult::ResultType::RETURN_VALUE: - mResultHolder->get()->Read(xpc::CurrentNativeGlobal(aCx), aCx, aResult, - aRv); - return; - case mozIExtensionAPIRequestResult::ResultType::EXTENSION_ERROR: - JS::RootedValue exn(aCx); - IgnoredErrorResult rv; - mResultHolder->get()->Read(xpc::CurrentNativeGlobal(aCx), aCx, &exn, rv); - if (rv.Failed()) { - NS_WARNING("Failed to deserialize extension error"); - ExtensionAPIBase::ThrowUnexpectedError(aCx, aRv); - return; - } - - aRv.MightThrowJSException(); - aRv.ThrowJSException(aCx, exn); - return; - } - - MOZ_DIAGNOSTIC_ASSERT(false, "Unexpected API request ResultType"); - aRv.Throw(NS_ERROR_UNEXPECTED); -} - -} // namespace extensions -} // namespace mozilla diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.h b/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.h deleted file mode 100644 index eae32eb1d00b..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.h +++ /dev/null @@ -1,194 +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_ExtensionAPIRequestForwarder_h -#define mozilla_extensions_ExtensionAPIRequestForwarder_h - -#include "ExtensionAPIRequest.h" - -#include "mozilla/dom/PromiseWorkerProxy.h" -#include "mozilla/dom/RootedDictionary.h" -#include "mozilla/dom/StructuredCloneHolder.h" -#include "mozilla/dom/WorkerRunnable.h" -#include "mozilla/dom/WorkerPrivate.h" -#include "mozilla/dom/ToJSValue.h" - -namespace mozilla { -namespace dom { -class ClientInfoAndState; -class Function; -class SerializedStackHolder; -} // namespace dom -namespace extensions { - -class ExtensionAPIRequestForwarder; - -// A class used to forward an API request (a method call, add/remote listener or -// a property getter) originated from a WebExtensions global (a window, a -// content script sandbox or a service worker) to the JS privileged API request -// handler available on the main thread (mozIExtensionAPIRequestHandler). -// -// Instances of this class are meant to be short-living, and destroyed when the -// caller function is exiting. -class ExtensionAPIRequestForwarder { - friend class ExtensionAPIRequest; - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ExtensionAPIRequestForwarder) - - public: - using APIRequestType = mozIExtensionAPIRequest::RequestType; - using APIResultType = mozIExtensionAPIRequestResult::ResultType; - - static nsresult JSArrayToSequence(JSContext* aCx, JS::HandleValue aJSValue, - dom::Sequence& aResult); - - static void ThrowUnexpectedError(JSContext* aCx, ErrorResult& aRv); - - static mozIExtensionAPIRequestHandler& APIRequestHandler(); - - ExtensionAPIRequestForwarder(const APIRequestType aRequestType, - const nsAString& aApiNamespace, - const nsAString& aApiMethod, - const nsAString& aApiObjectType = u""_ns, - const nsAString& aApiObjectId = u""_ns); - - mozIExtensionAPIRequest::RequestType GetRequestType() const { - return mRequestType; - } - - const ExtensionAPIRequestTarget* GetRequestTarget() { - return &mRequestTarget; - } - - void Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, ErrorResult& aRv); - - void Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - ExtensionEventListener* aListener, ErrorResult& aRv); - - void Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - JS::MutableHandleValue aRetVal, ErrorResult& aRv); - - void Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - ExtensionEventListener* aListener, JS::MutableHandleValue aRetVal, - ErrorResult& aRv); - - void Run(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - const RefPtr& aPromiseRetval, ErrorResult& aRv); - - void Run(nsIGlobalObject* aGlobal, JSContext* aCx, - JS::MutableHandleValue aRetVal, ErrorResult& aRv); - - protected: - virtual ~ExtensionAPIRequestForwarder() = default; - - private: - already_AddRefed CreateAPIRequest( - nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, ExtensionEventListener* aListener, - ErrorResult& aRv); - - APIRequestType mRequestType; - ExtensionAPIRequestTarget mRequestTarget; -}; - -/* - * This runnable is used internally by ExtensionAPIRequestForwader class - * to call the JS privileged code that handle the API requests originated - * from the WebIDL bindings instantiated in a worker thread. - * - * The runnable is meant to block the worker thread until we get a result - * from the JS privileged code that handles the API request. - * - * For async API calls we still need to block the worker thread until - * we get a promise (which we link to the worker thread promise and - * at that point we unblock the worker thread), because the JS privileged - * code handling the API request may need to throw some errors synchonously - * (e.g. in case of additional validations based on the API schema definition - * for the parameter, like strings that has to pass additional validation - * or normalizations). - */ -class RequestWorkerRunnable : public dom::WorkerMainThreadRunnable { - public: - using APIRequestType = mozIExtensionAPIRequest::RequestType; - using APIResultType = mozIExtensionAPIRequestResult::ResultType; - - RequestWorkerRunnable(dom::WorkerPrivate* aWorkerPrivate, - ExtensionAPIRequestForwarder* aOuterAPIRequest); - - /** - * Init a request runnable for AddListener and RemoveListener API requests - * (which do have an event callback callback and do not expect any return - * value). - */ - void Init(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - ExtensionEventListener* aListener, ErrorResult& aRv); - - /** - * Init a request runnable for CallFunctionNoReturn API requests (which do - * do not expect any return value). - */ - void Init(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, ErrorResult& aRv) { - Init(aGlobal, aCx, aArgs, nullptr, aRv); - } - - /** - * Init a request runnable for CallAsyncFunction API requests (which do - * expect a promise as return value). - */ - void Init(nsIGlobalObject* aGlobal, JSContext* aCx, - const dom::Sequence& aArgs, - const RefPtr& aPromiseRetval, ErrorResult& aRv); - - bool MainThreadRun() override; - - void ReadResult(JSContext* aCx, JS::MutableHandleValue aResult, - ErrorResult& aRv); - - Maybe GetResultType() { - return mResultType; - } - - protected: - virtual bool ProcessHandlerResult(JSContext* aCx, - JS::MutableHandleValue aRetval); - - already_AddRefed GetWebExtensionPolicy(); - already_AddRefed CreateAPIRequest(JSContext* aCx); - - void SerializeCallerStack(JSContext* aCx); - void DeserializeCallerStack(JSContext* aCx, JS::MutableHandleValue aRetval); - void SerializeArgs(JSContext* aCx, const dom::Sequence& aArgs, - ErrorResult& aRv); - nsresult DeserializeArgs(JSContext* aCx, JS::MutableHandle aArgs); - - bool HandleAPIRequest(JSContext* aCx, JS::MutableHandleValue aRetval); - - Maybe mResultType; - Maybe> mResultHolder; - RefPtr mPromiseProxy; - Maybe> mArgsHolder; - Maybe> mStackHolder; - Maybe mClientInfo; - - // Only set for addListener/removeListener API requests. - RefPtr mEventListener; - - // The outer request object is kept alive by the caller for the - // entire life of the inner worker runnable. - ExtensionAPIRequestForwarder* mOuterRequest; -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionAPIRequestForwarder_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionBrowser.cpp b/toolkit/components/extensions/webidl-api/ExtensionBrowser.cpp deleted file mode 100644 index 55890332999f..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionBrowser.cpp +++ /dev/null @@ -1,81 +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/. */ - -#include "ExtensionBrowser.h" - -#include "mozilla/dom/ExtensionBrowserBinding.h" -#include "mozilla/dom/WorkerPrivate.h" // GetWorkerPrivateFromContext -#include "mozilla/extensions/ExtensionMockAPI.h" -#include "mozilla/extensions/WebExtensionPolicy.h" - -namespace mozilla { -namespace extensions { - -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 - -ExtensionBrowser::ExtensionBrowser(nsIGlobalObject* aGlobal) - : mGlobal(aGlobal) { - MOZ_DIAGNOSTIC_ASSERT(mGlobal); -} - -JSObject* ExtensionBrowser::WrapObject(JSContext* aCx, - JS::Handle aGivenProto) { - return dom::ExtensionBrowser_Binding::Wrap(aCx, this, aGivenProto); -} - -nsIGlobalObject* ExtensionBrowser::GetParentObject() const { return mGlobal; } - -bool ExtensionAPIAllowed(JSContext* aCx, JSObject* aGlobal) { -#ifdef MOZ_WEBEXT_WEBIDL_ENABLED - // Only expose the Extension API bindings if: - // - the context is related to a worker where the Extension API are allowed - // (currently only the extension service worker declared in the extension - // manifest met this condition) - // - the global is an extension window or an extension content script sandbox - // TODO: - // - the support for the extension window is deferred to a followup. - // - support for the content script sandboxes is also deferred to follow-ups - // - lock native Extension API in an extension window or sandbox behind a - // separate pref. - MOZ_DIAGNOSTIC_ASSERT( - !NS_IsMainThread(), - "ExtensionAPI webidl bindings does not yet support main thread globals"); - - // Verify if the Extensions API should be allowed on a worker thread. - if (!StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup()) { - return false; - } - - auto* workerPrivate = mozilla::dom::GetWorkerPrivateFromContext(aCx); - MOZ_ASSERT(workerPrivate); - MOZ_ASSERT(workerPrivate->IsServiceWorker()); - - return workerPrivate->ExtensionAPIAllowed(); -#else - // Always return false on build where MOZ_WEBEXT_WEBIDL_ENABLED is set to - // false (currently on all channels but nightly). - return false; -#endif -} - -ExtensionMockAPI* ExtensionBrowser::GetExtensionMockAPI() { - if (!mExtensionMockAPI) { - mExtensionMockAPI = new ExtensionMockAPI(mGlobal, this); - } - - return mExtensionMockAPI; -} - -} // namespace extensions -} // namespace mozilla diff --git a/toolkit/components/extensions/webidl-api/ExtensionBrowser.h b/toolkit/components/extensions/webidl-api/ExtensionBrowser.h deleted file mode 100644 index 41342a723b90..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionBrowser.h +++ /dev/null @@ -1,52 +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_ExtensionBrowser_h -#define mozilla_extensions_ExtensionBrowser_h - -#include "nsCOMPtr.h" -#include "nsISupports.h" -#include "nsWrapperCache.h" - -class nsIGlobalObject; - -namespace mozilla { - -class ErrorResult; - -namespace extensions { - -class ExtensionMockAPI; - -bool ExtensionAPIAllowed(JSContext* aCx, JSObject* aGlobal); - -class ExtensionBrowser final : public nsISupports, public nsWrapperCache { - nsCOMPtr mGlobal; - RefPtr mExtensionMockAPI; - - ~ExtensionBrowser() = default; - - public: - explicit ExtensionBrowser(nsIGlobalObject* aGlobal); - - // nsWrapperCache interface methods - JSObject* WrapObject(JSContext* aCx, - JS::Handle aGivenProto) override; - - // DOM bindings methods - - nsIGlobalObject* GetParentObject() const; - - ExtensionMockAPI* GetExtensionMockAPI(); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionBrowser) -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionBrowser_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionEventListener.cpp b/toolkit/components/extensions/webidl-api/ExtensionEventListener.cpp deleted file mode 100644 index 777cc30eaa4e..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionEventListener.cpp +++ /dev/null @@ -1,676 +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 "ExtensionEventListener.h" -#include "ExtensionPort.h" - -#include "mozilla/dom/FunctionBinding.h" -#include "nsJSPrincipals.h" // nsJSPrincipals::AutoSetActiveWorkerPrincipal -#include "nsThreadManager.h" // NS_IsMainThread - -namespace mozilla { -namespace extensions { - -namespace { - -class SendResponseCallback final : public nsISupports { - public: - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SendResponseCallback) - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - - static RefPtr Create( - nsIGlobalObject* aGlobalObject, const RefPtr& aPromise, - JS::Handle aValue, ErrorResult& aRv) { - MOZ_ASSERT(dom::IsCurrentThreadRunningWorker()); - - RefPtr responseCallback = - new SendResponseCallback(aPromise, aValue); - - auto cleanupCb = [responseCallback]() { responseCallback->Cleanup(); }; - - // Create a StrongWorkerRef to the worker thread, the cleanup callback - // associated to the StongerWorkerRef will release the reference and resolve - // the promise returned to the ExtensionEventListener caller with undefined - // if the worker global is being destroyed. - auto* workerPrivate = dom::GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - workerPrivate->AssertIsOnWorkerThread(); - - RefPtr workerRef = dom::StrongWorkerRef::Create( - workerPrivate, "SendResponseCallback", cleanupCb); - if (NS_WARN_IF(!workerRef)) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - responseCallback->mWorkerRef = workerRef; - - return responseCallback; - } - - SendResponseCallback(const RefPtr& aPromise, - JS::Handle aValue) - : mPromise(aPromise), mValue(aValue) { - MOZ_ASSERT(mPromise); - mozilla::HoldJSObjects(this); - - // Create a promise monitor that invalidates the sendResponse - // callback if the promise has been already resolved or rejected. - mPromiseListener = new dom::DomPromiseListener( - mPromise, - [self = RefPtr{this}](JSContext* aCx, JS::Handle aValue) { - self->Cleanup(); - }, - [self = RefPtr{this}](nsresult aError) { self->Cleanup(); }); - } - - void Cleanup(bool aIsDestroying = false) { - // Return earlier if the instance was already been cleaned up. - if (!mPromiseListener) { - return; - } - - NS_WARNING("SendResponseCallback::Cleanup"); - // Override the promise listener's resolvers to release the - // RefPtr captured by the ones initially set. - mPromiseListener->SetResolvers( - [](JSContext* aCx, JS::Handle aValue) {}, - [](nsresult aError) {}); - mPromiseListener = nullptr; - - if (mPromise) { - mPromise->MaybeResolveWithUndefined(); - } - mPromise = nullptr; - - // Skipped if called from the destructor. - if (!aIsDestroying && mValue.isObject()) { - // Release the reference to the SendResponseCallback. - js::SetFunctionNativeReserved(&mValue.toObject(), - SLOT_SEND_RESPONSE_CALLBACK_INSTANCE, - JS::PrivateValue(nullptr)); - } - - if (mWorkerRef) { - mWorkerRef = nullptr; - } - } - - static bool Call(JSContext* aCx, unsigned aArgc, JS::Value* aVp) { - JS::CallArgs args = CallArgsFromVp(aArgc, aVp); - JS::Rooted callee(aCx, &args.callee()); - - JS::Value v = js::GetFunctionNativeReserved( - callee, SLOT_SEND_RESPONSE_CALLBACK_INSTANCE); - - SendResponseCallback* sendResponse = - reinterpret_cast(v.toPrivate()); - if (!sendResponse || !sendResponse->mPromise || - !sendResponse->mPromise->PromiseObj()) { - NS_WARNING("SendResponseCallback called after being invalidated"); - return true; - } - - sendResponse->mPromise->MaybeResolve(args.get(0)); - sendResponse->Cleanup(); - - return true; - } - - private: - ~SendResponseCallback() { - mozilla::DropJSObjects(this); - this->Cleanup(true); - }; - - RefPtr mPromise; - RefPtr mPromiseListener; - JS::Heap mValue; - RefPtr mWorkerRef; -}; - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SendResponseCallback) - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTION_CLASS(SendResponseCallback) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(SendResponseCallback) -NS_IMPL_CYCLE_COLLECTING_RELEASE(SendResponseCallback) - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SendResponseCallback) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(SendResponseCallback) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mValue) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SendResponseCallback) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromiseListener); - tmp->mValue.setUndefined(); - // Resolve the promise with undefined (as "unhandled") before unlinking it. - if (tmp->mPromise) { - tmp->mPromise->MaybeResolveWithUndefined(); - } - NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -} // anonymous namespace - -// ExtensionEventListener - -NS_IMPL_ISUPPORTS(ExtensionEventListener, mozIExtensionEventListener) - -// static -already_AddRefed ExtensionEventListener::Create( - nsIGlobalObject* aGlobal, dom::Function* aCallback, - CleanupCallback&& aCleanupCallback, ErrorResult& aRv) { - MOZ_ASSERT(dom::IsCurrentThreadRunningWorker()); - RefPtr extCb = - new ExtensionEventListener(aGlobal, aCallback); - - auto* workerPrivate = dom::GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - workerPrivate->AssertIsOnWorkerThread(); - RefPtr workerRef = dom::StrongWorkerRef::Create( - workerPrivate, "ExtensionEventListener", std::move(aCleanupCallback)); - if (!workerRef) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - extCb->mWorkerRef = new dom::ThreadSafeWorkerRef(workerRef); - - return extCb.forget(); -} - -// static -UniquePtr -ExtensionEventListener::SerializeCallArguments(const nsTArray& aArgs, - JSContext* aCx, - ErrorResult& aRv) { - JS::Rooted jsval(aCx); - if (NS_WARN_IF(!dom::ToJSValue(aCx, aArgs, &jsval))) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - UniquePtr argsHolder = - MakeUnique( - dom::StructuredCloneHolder::CloningSupported, - dom::StructuredCloneHolder::TransferringNotSupported, - JS::StructuredCloneScope::SameProcess); - - argsHolder->Write(aCx, jsval, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - return argsHolder; -} - -NS_IMETHODIMP ExtensionEventListener::CallListener( - const nsTArray& aArgs, ListenerCallOptions* aCallOptions, - JSContext* aCx, dom::Promise** aPromiseResult) { - MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_ARG_POINTER(aPromiseResult); - - // Process and validate call options. - APIObjectType apiObjectType = APIObjectType::NONE; - JS::Rooted apiObjectDescriptor(aCx); - if (aCallOptions) { - aCallOptions->GetApiObjectType(&apiObjectType); - aCallOptions->GetApiObjectDescriptor(&apiObjectDescriptor); - - // Explicitly check that the APIObjectType is one of expected ones, - // raise to the caller an explicit error if it is not. - // - // This is using a switch to also get a warning if a new value is added to - // the APIObjectType enum and it is not yet handled. - switch (apiObjectType) { - case APIObjectType::NONE: - if (NS_WARN_IF(!apiObjectDescriptor.isNullOrUndefined())) { - JS_ReportErrorASCII( - aCx, - "Unexpected non-null apiObjectDescriptor on apiObjectType=NONE"); - return NS_ERROR_UNEXPECTED; - } - break; - case APIObjectType::RUNTIME_PORT: - if (NS_WARN_IF(apiObjectDescriptor.isNullOrUndefined())) { - JS_ReportErrorASCII(aCx, - "Unexpected null apiObjectDescriptor on " - "apiObjectType=RUNTIME_PORT"); - return NS_ERROR_UNEXPECTED; - } - break; - default: - MOZ_CRASH("Unexpected APIObjectType"); - return NS_ERROR_UNEXPECTED; - } - } - - // Create promise to be returned. - IgnoredErrorResult rv; - RefPtr retPromise; - - nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx); - if (NS_WARN_IF(!global)) { - return NS_ERROR_FAILURE; - } - retPromise = dom::Promise::Create(global, rv); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - // Convert args into a non-const sequence. - dom::Sequence args; - if (!args.AppendElements(aArgs, fallible)) { - return NS_ERROR_OUT_OF_MEMORY; - } - - // Execute the listener call. - - MutexAutoLock lock(mMutex); - - if (NS_WARN_IF(!mWorkerRef)) { - return NS_ERROR_ABORT; - } - - if (apiObjectType != APIObjectType::NONE) { - // Prepend the apiObjectDescriptor data to the call arguments, - // the worker runnable will convert that into an API object - // instance on the worker thread. - if (!args.InsertElementAt(0, std::move(apiObjectDescriptor), fallible)) { - return NS_ERROR_OUT_OF_MEMORY; - } - } - - UniquePtr argsHolder = - SerializeCallArguments(args, aCx, rv); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - RefPtr runnable = - new ExtensionListenerCallWorkerRunnable(this, std::move(argsHolder), - aCallOptions, retPromise); - runnable->Dispatch(); - retPromise.forget(aPromiseResult); - - return NS_OK; -} - -dom::WorkerPrivate* ExtensionEventListener::GetWorkerPrivate() const { - MOZ_ASSERT(mWorkerRef); - return mWorkerRef->Private(); -} - -// ExtensionListenerCallWorkerRunnable - -void ExtensionListenerCallWorkerRunnable::DeserializeCallArguments( - JSContext* aCx, dom::Sequence& aArgs, ErrorResult& aRv) { - JS::Rooted jsvalue(aCx); - - mArgsHolder->Read(xpc::CurrentNativeGlobal(aCx), aCx, &jsvalue, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - nsresult rv2 = - ExtensionAPIRequestForwarder::JSArrayToSequence(aCx, jsvalue, aArgs); - if (NS_FAILED(rv2)) { - aRv.Throw(rv2); - } -} - -bool ExtensionListenerCallWorkerRunnable::WorkerRun( - JSContext* aCx, dom::WorkerPrivate* aWorkerPrivate) { - MOZ_ASSERT(aWorkerPrivate); - aWorkerPrivate->AssertIsOnWorkerThread(); - MOZ_ASSERT(aWorkerPrivate == mWorkerPrivate); - auto global = mListener->GetGlobalObject(); - if (NS_WARN_IF(!global)) { - return true; - } - - auto fn = mListener->GetCallback(); - if (NS_WARN_IF(!fn)) { - return true; - } - - IgnoredErrorResult rv; - dom::Sequence argsSequence; - dom::SequenceRooter arguments(aCx, &argsSequence); - - DeserializeCallArguments(aCx, argsSequence, rv); - if (NS_WARN_IF(rv.Failed())) { - return true; - } - - RefPtr retPromise; - RefPtr workerRef; - - retPromise = dom::Promise::Create(global, rv); - if (retPromise) { - workerRef = dom::StrongWorkerRef::Create( - aWorkerPrivate, "ExtensionListenerCallWorkerRunnable", []() {}); - } - - if (NS_WARN_IF(rv.Failed() || !workerRef)) { - auto rejectMainThreadPromise = - [error = rv.Failed() ? rv.StealNSResult() : NS_ERROR_UNEXPECTED, - promiseResult = std::move(mPromiseResult)]() { - // TODO(rpl): this seems to be currently rejecting an error object - // without a stack trace, its a corner case but we may look into - // improve this error. - promiseResult->MaybeReject(error); - }; - - nsCOMPtr runnable = - NS_NewRunnableFunction(__func__, std::move(rejectMainThreadPromise)); - NS_DispatchToMainThread(runnable); - JS_ClearPendingException(aCx); - return true; - } - - ExtensionListenerCallPromiseResultHandler::Create( - retPromise, this, new dom::ThreadSafeWorkerRef(workerRef)); - - // Translate the first parameter into the API object type (e.g. an - // ExtensionPort), the content of the original argument value is expected to - // be a dictionary that is valid as an internal descriptor for that API object - // type. - if (mAPIObjectType != APIObjectType::NONE) { - IgnoredErrorResult rv; - - // The api object descriptor is expected to have been prepended to the - // other arguments, assert here that the argsSequence does contain at least - // one element. - MOZ_ASSERT(!argsSequence.IsEmpty()); - - JS::Rooted apiObjectDescriptor(aCx, argsSequence.ElementAt(0)); - JS::Rooted apiObjectValue(aCx); - - // We only expect the object type to be RUNTIME_PORT at the moment, - // until we will need to expect it to support other object types that - // some specific API may need. - MOZ_ASSERT(mAPIObjectType == APIObjectType::RUNTIME_PORT); - RefPtr port = - ExtensionPort::Create(global, apiObjectDescriptor, rv); - if (NS_WARN_IF(rv.Failed())) { - retPromise->MaybeReject(rv.StealNSResult()); - return true; - } - - if (NS_WARN_IF(!dom::ToJSValue(aCx, port, &apiObjectValue))) { - retPromise->MaybeReject(NS_ERROR_UNEXPECTED); - return true; - } - - argsSequence.ReplaceElementAt(0, apiObjectValue); - } - - // Create callback argument and append it to the call arguments. - JS::Rooted sendResponseObj(aCx); - - switch (mCallbackArgType) { - case CallbackType::CALLBACK_NONE: - break; - case CallbackType::CALLBACK_SEND_RESPONSE: { - JS::Rooted sendResponseFn( - aCx, js::NewFunctionWithReserved(aCx, SendResponseCallback::Call, - /* nargs */ 1, 0, "sendResponse")); - sendResponseObj = JS_GetFunctionObject(sendResponseFn); - JS::RootedValue sendResponseValue(aCx, JS::ObjectValue(*sendResponseObj)); - - // Create a SendResponseCallback instance that keeps a reference - // to the promise to resolve when the static SendReponseCallback::Call - // is being called. - // the SendReponseCallback instance from the resolved slot to resolve - // the promise and invalidated the sendResponse callback (any new call - // becomes a noop). - RefPtr sendResponsePtr = - SendResponseCallback::Create(global, retPromise, sendResponseValue, - rv); - if (NS_WARN_IF(rv.Failed())) { - retPromise->MaybeReject(NS_ERROR_UNEXPECTED); - return true; - } - - // Store the SendResponseCallback instance in a private value set on the - // function object reserved slot, where ehe SendResponseCallback::Call - // static function will get it back to resolve the related promise - // and then invalidate the sendResponse callback (any new call - // becomes a noop). - js::SetFunctionNativeReserved(sendResponseObj, - SLOT_SEND_RESPONSE_CALLBACK_INSTANCE, - JS::PrivateValue(sendResponsePtr)); - - if (NS_WARN_IF( - !argsSequence.AppendElement(sendResponseValue, fallible))) { - retPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY); - return true; - } - - break; - } - default: - MOZ_ASSERT_UNREACHABLE("Unexpected callbackType"); - break; - } - - // TODO: should `nsAutoMicroTask mt;` be used here? - dom::AutoEntryScript aes(global, "WebExtensionAPIEvent"); - JS::Rooted retval(aCx); - ErrorResult erv; - erv.MightThrowJSException(); - MOZ_KnownLive(fn)->Call(argsSequence, &retval, erv, "WebExtensionAPIEvent", - dom::Function::eRethrowExceptions); - - // Calling the callback may have thrown an exception. - // TODO: add a ListenerCallOptions to optionally report the exception - // instead of forwarding it to the caller. - erv.WouldReportJSException(); - - if (erv.Failed()) { - retPromise->MaybeReject(std::move(erv)); - return true; - } - - // Custom return value handling logic for events that do pass a - // sendResponse callback parameter (see expected behavior - // for the runtime.onMessage sendResponse parameter on MDN: - // https://mzl.la/3dokpMi): - // - // - listener returns Boolean true => the extension listener is - // expected to call sendResponse callback parameter asynchronosuly - // - listener return a Promise object => the promise is the listener - // response - // - listener return any other value => the listener didn't handle the - // event and the return value is ignored - // - if (mCallbackArgType == CallbackType::CALLBACK_SEND_RESPONSE) { - if (retval.isBoolean() && retval.isTrue()) { - // The listener returned `true` and so the promise relate to the - // listener call will be resolved once the extension will call - // the sendResponce function passed as a callback argument. - return true; - } - - // If the retval isn't true and it is not a Promise object, - // the listener isn't handling the event, and we resolve the - // promise with undefined (if the listener didn't reply already - // by calling sendResponse synchronsouly). - // undefined ( - if (!ExtensionEventListener::IsPromise(aCx, retval)) { - // Mark this listener call as cancelled, ExtensionListenerCallPromiseResult - // will check to know that it should release the main thread promise without - // resolving it. - // - // TODO: double-check if we should also cancel rejecting the promise returned by - // mozIExtensionEventListener.callListener when the listener call throws (by - // comparing it with the behavior on the current privileged-based API implementation). - mIsCallResultCancelled = true; - retPromise->MaybeResolveWithUndefined(); - - // Invalidate the sendResponse function by setting the private - // value where the SendResponseCallback instance was stored - // to a nullptr. - js::SetFunctionNativeReserved(sendResponseObj, - SLOT_SEND_RESPONSE_CALLBACK_INSTANCE, - JS::PrivateValue(nullptr)); - - return true; - } - } - - retPromise->MaybeResolve(retval); - - return true; -} - -// ExtensionListenerCallPromiseResultHandler - -NS_IMPL_ISUPPORTS0(ExtensionListenerCallPromiseResultHandler) - -// static -void ExtensionListenerCallPromiseResultHandler::Create( - const RefPtr& aPromise, - const RefPtr& aWorkerRunnable, - dom::ThreadSafeWorkerRef* aWorkerRef) { - MOZ_ASSERT(aPromise); - MOZ_ASSERT(aWorkerRef); - MOZ_ASSERT(aWorkerRef->Private()->IsOnCurrentThread()); - - RefPtr handler = - new ExtensionListenerCallPromiseResultHandler(aWorkerRef, - aWorkerRunnable); - aPromise->AppendNativeHandler(handler); -} - -void ExtensionListenerCallPromiseResultHandler::WorkerRunCallback( - JSContext* aCx, JS::Handle aValue, - PromiseCallbackType aCallbackType) { - MOZ_ASSERT(mWorkerRef); - mWorkerRef->Private()->AssertIsOnWorkerThread(); - - // The listener call was cancelled (e.g. when a runtime.onMessage listener - // returned false), release resources associated with this promise handler - // on the main thread without resolving the promise associated to the - // extension event listener call. - if (mWorkerRunnable->IsCallResultCancelled()) { - auto releaseMainThreadPromise = [runnable = std::move(mWorkerRunnable), - workerRef = std::move(mWorkerRef)]() {}; - nsCOMPtr runnable = - NS_NewRunnableFunction(__func__, std::move(releaseMainThreadPromise)); - NS_DispatchToMainThread(runnable); - return; - } - - JS::RootedValue retval(aCx, aValue); - - if (retval.isObject()) { - // Try to serialize the result as an ClonedErrorHolder, - // in case the value is an Error object. - IgnoredErrorResult rv; - JS::Rooted errObj(aCx, &retval.toObject()); - RefPtr ceh = - dom::ClonedErrorHolder::Create(aCx, errObj, rv); - if (!rv.Failed() && ceh) { - JS::RootedObject obj(aCx); - // Note: `ToJSValue` cannot be used because ClonedErrorHolder isn't - // wrapped cached. - Unused << NS_WARN_IF(!ceh->WrapObject(aCx, nullptr, &obj)); - retval.setObject(*obj); - } - } - - UniquePtr resHolder = - MakeUnique( - dom::StructuredCloneHolder::CloningSupported, - dom::StructuredCloneHolder::TransferringNotSupported, - JS::StructuredCloneScope::SameProcess); - - IgnoredErrorResult erv; - resHolder->Write(aCx, retval, erv); - - // Failed to serialize the result, dispatch a runnable to reject - // the promise returned to the caller of the mozIExtensionCallback - // callWithPromiseResult method. - if (NS_WARN_IF(erv.Failed())) { - auto rejectMainThreadPromise = [error = erv.StealNSResult(), - runnable = std::move(mWorkerRunnable), - resHolder = std::move(resHolder)]() { - RefPtr promiseResult = std::move(runnable->mPromiseResult); - promiseResult->MaybeReject(error); - }; - - nsCOMPtr runnable = - NS_NewRunnableFunction(__func__, std::move(rejectMainThreadPromise)); - NS_DispatchToMainThread(runnable); - JS_ClearPendingException(aCx); - return; - } - - auto resolveMainThreadPromise = [callbackType = aCallbackType, - resHolder = std::move(resHolder), - runnable = std::move(mWorkerRunnable), - workerRef = std::move(mWorkerRef)]() { - RefPtr promiseResult = std::move(runnable->mPromiseResult); - - auto* global = promiseResult->GetGlobalObject(); - dom::AutoEntryScript aes(global, - "ExtensionListenerCallWorkerRunnable::WorkerRun"); - JSContext* cx = aes.cx(); - JS::Rooted jsvalue(cx); - IgnoredErrorResult rv; - - { - // Set the active worker principal while reading the result, - // needed to be sure to be able to successfully deserialize the - // SavedFrame part of a ClonedErrorHolder (in case that was the - // result stored in the StructuredCloneHolder). - Maybe set; - if (workerRef) { - set.emplace(workerRef->Private()->GetPrincipal()); - } - - resHolder->Read(global, cx, &jsvalue, rv); - } - - if (NS_WARN_IF(rv.Failed())) { - promiseResult->MaybeReject(rv.StealNSResult()); - JS_ClearPendingException(cx); - } else { - switch (callbackType) { - case PromiseCallbackType::Resolve: - promiseResult->MaybeResolve(jsvalue); - break; - case PromiseCallbackType::Reject: - promiseResult->MaybeReject(jsvalue); - break; - } - } - }; - - nsCOMPtr runnable = - NS_NewRunnableFunction(__func__, std::move(resolveMainThreadPromise)); - NS_DispatchToMainThread(runnable); -} - -void ExtensionListenerCallPromiseResultHandler::ResolvedCallback( - JSContext* aCx, JS::Handle aValue) { - WorkerRunCallback(aCx, aValue, PromiseCallbackType::Resolve); -} - -void ExtensionListenerCallPromiseResultHandler::RejectedCallback( - JSContext* aCx, JS::Handle aValue) { - WorkerRunCallback(aCx, aValue, PromiseCallbackType::Reject); -} - -} // namespace extensions -} // namespace mozilla diff --git a/toolkit/components/extensions/webidl-api/ExtensionEventListener.h b/toolkit/components/extensions/webidl-api/ExtensionEventListener.h deleted file mode 100644 index be47dcd659ea..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionEventListener.h +++ /dev/null @@ -1,217 +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_ExtensionEventListener_h -#define mozilla_extensions_ExtensionEventListener_h - -#include "js/Promise.h" // JS::IsPromiseObject -#include "mozIExtensionAPIRequestHandling.h" -#include "mozilla/dom/PromiseNativeHandler.h" -#include "mozilla/dom/StructuredCloneHolder.h" -#include "mozilla/dom/WorkerRunnable.h" -#include "mozilla/dom/WorkerPrivate.h" - -class nsIGlobalObject; - -namespace mozilla { - -namespace dom { -class Function; -} // namespace dom - -namespace extensions { - -#define SLOT_SEND_RESPONSE_CALLBACK_INSTANCE 0 - -// A class that represents a callback parameter passed to WebExtensions API -// addListener / removeListener methods. -// -// Instances of this class are sent to the mozIExtensionAPIRequestHandler as -// a property of the mozIExtensionAPIRequest. -// -// The mozIExtensionEventListener xpcom interface provides methods that allow -// the mozIExtensionAPIRequestHandler running in the Main Thread to call the -// underlying callback Function on its owning thread. -class ExtensionEventListener final : public mozIExtensionEventListener { - public: - NS_DECL_MOZIEXTENSIONEVENTLISTENER - NS_DECL_THREADSAFE_ISUPPORTS - - using CleanupCallback = std::function; - using ListenerCallOptions = mozIExtensionListenerCallOptions; - using APIObjectType = ListenerCallOptions::APIObjectType; - using CallbackType = ListenerCallOptions::CallbackType; - - static already_AddRefed Create( - nsIGlobalObject* aGlobal, dom::Function* aCallback, - CleanupCallback&& aCleanupCallback, ErrorResult& aRv); - - static bool IsPromise(JSContext* aCx, JS::Handle aValue) { - if (!aValue.isObject()) { - return false; - } - - JS::Rooted obj(aCx, &aValue.toObject()); - return JS::IsPromiseObject(obj); - } - - dom::WorkerPrivate* GetWorkerPrivate() const; - - RefPtr GetCallback() const { return mCallback; } - - nsCOMPtr GetGlobalObject() const { - nsCOMPtr global = do_QueryReferent(mGlobal); - return global; - } - - void Cleanup() { - if (mWorkerRef) { - MutexAutoLock lock(mMutex); - - mWorkerRef->Private()->AssertIsOnWorkerThread(); - mWorkerRef = nullptr; - } - - mGlobal = nullptr; - mCallback = nullptr; - } - - private: - ExtensionEventListener(nsIGlobalObject* aGlobal, dom::Function* aCallback) - : mGlobal(do_GetWeakReference(aGlobal)), - mCallback(aCallback), - mMutex("ExtensionEventListener::mMutex"){}; - - static UniquePtr SerializeCallArguments( - const nsTArray& aArgs, JSContext* aCx, ErrorResult& aRv); - - ~ExtensionEventListener() { Cleanup(); }; - - // Accessed on the main and on the owning threads. - RefPtr mWorkerRef; - - // Accessed only on the owning thread. - nsWeakPtr mGlobal; - RefPtr mCallback; - - // Used to make sure we are not going to release the - // instance on the worker thread, while we are in the - // process of forwarding a call from the main thread. - Mutex mMutex; -}; - -// A WorkerRunnable subclass used to call an ExtensionEventListener -// in the thread that owns the dom::Function wrapped by the -// ExtensionEventListener class. -class ExtensionListenerCallWorkerRunnable : public dom::WorkerRunnable { - friend class ExtensionListenerCallPromiseResultHandler; - - public: - using ListenerCallOptions = mozIExtensionListenerCallOptions; - using APIObjectType = ListenerCallOptions::APIObjectType; - using CallbackType = ListenerCallOptions::CallbackType; - - ExtensionListenerCallWorkerRunnable( - const RefPtr& aExtensionEventListener, - UniquePtr aArgsHolder, - ListenerCallOptions* aCallOptions, - RefPtr aPromiseRetval = nullptr) - : WorkerRunnable(aExtensionEventListener->GetWorkerPrivate(), - WorkerThreadUnchangedBusyCount), - mListener(aExtensionEventListener), - mArgsHolder(std::move(aArgsHolder)), - mPromiseResult(std::move(aPromiseRetval)), - mAPIObjectType(APIObjectType::NONE), - mCallbackArgType(CallbackType::CALLBACK_NONE) { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aExtensionEventListener); - - if (aCallOptions) { - aCallOptions->GetApiObjectType(&mAPIObjectType); - aCallOptions->GetCallbackType(&mCallbackArgType); - } - } - - MOZ_CAN_RUN_SCRIPT_BOUNDARY - bool WorkerRun(JSContext* aCx, dom::WorkerPrivate* aWorkerPrivate) override; - - bool IsCallResultCancelled() { - return mIsCallResultCancelled; - } - - private: - ~ExtensionListenerCallWorkerRunnable() { - NS_ReleaseOnMainThread(mPromiseResult.forget()); - ReleaseArgsHolder(); - mListener = nullptr; - } - - void ReleaseArgsHolder() { - if (NS_IsMainThread()) { - mArgsHolder = nullptr; - } else { - auto releaseArgsHolder = [argsHolder = std::move(mArgsHolder)]() {}; - nsCOMPtr runnable = - NS_NewRunnableFunction(__func__, std::move(releaseArgsHolder)); - NS_DispatchToMainThread(runnable); - } - } - - void DeserializeCallArguments(JSContext* aCx, dom::Sequence& aArg, - ErrorResult& aRv); - - RefPtr mListener; - UniquePtr mArgsHolder; - RefPtr mPromiseResult; - bool mIsCallResultCancelled = false; - // Call Options. - APIObjectType mAPIObjectType; - CallbackType mCallbackArgType; -}; - -// A class attached to the promise that should be resolved once the extension -// event listener call has been handled, responsible for serializing resolved -// values or rejected errors on the listener's owning thread and sending them to -// the extension event listener caller running on the main thread. -class ExtensionListenerCallPromiseResultHandler - : public dom::PromiseNativeHandler { - public: - NS_DECL_THREADSAFE_ISUPPORTS - - static void Create( - const RefPtr& aPromise, - const RefPtr& aWorkerRunnable, - dom::ThreadSafeWorkerRef* aWorkerRef); - - // PromiseNativeHandler - void ResolvedCallback(JSContext* aCx, JS::Handle aValue) override; - void RejectedCallback(JSContext* aCx, JS::Handle aValue) override; - - enum class PromiseCallbackType { Resolve, Reject }; - - private: - ExtensionListenerCallPromiseResultHandler( - dom::ThreadSafeWorkerRef* aWorkerRef, - RefPtr aWorkerRunnable) - : mWorkerRef(aWorkerRef), mWorkerRunnable(std::move(aWorkerRunnable)) {} - - ~ExtensionListenerCallPromiseResultHandler() = default; - - void WorkerRunCallback(JSContext* aCx, JS::Handle aValue, - PromiseCallbackType aCallbackType); - - // Set and accessed only on the owning worker thread. - RefPtr mWorkerRef; - - // Reference to the runnable created on and owned by the main thread, - // accessed on the worker thread and released on the owning thread. - RefPtr mWorkerRunnable; -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionEventListener_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionEventManager.cpp b/toolkit/components/extensions/webidl-api/ExtensionEventManager.cpp deleted file mode 100644 index 13667dd0855c..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionEventManager.cpp +++ /dev/null @@ -1,155 +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 "ExtensionEventManager.h" - -#include "mozilla/dom/ExtensionEventManagerBinding.h" -#include "nsIGlobalObject.h" -#include "ExtensionEventListener.h" - -namespace mozilla { -namespace extensions { - -NS_IMPL_CYCLE_COLLECTION_CLASS(ExtensionEventManager); -NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionEventManager); -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_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_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ExtensionEventManager) - for (auto iter = tmp->mListeners.iter(); !iter.done(); iter.next()) { - aCallbacks.Trace(&iter.get().mutableKey(), "mListeners key", aClosure); - } - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionEventManager) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -ExtensionEventManager::ExtensionEventManager(nsIGlobalObject* aGlobal, - const nsAString& aNamespace, - const nsAString& aEventName, - const nsAString& aObjectType, - const nsAString& aObjectId) - : mGlobal(aGlobal), - mAPINamespace(aNamespace), - mEventName(aEventName), - mAPIObjectType(aObjectType), - mAPIObjectId(aObjectId) { - MOZ_DIAGNOSTIC_ASSERT(mGlobal); - - RefPtr self = this; - mozilla::HoldJSObjects(this); -} - -ExtensionEventManager::~ExtensionEventManager() { - ReleaseListeners(); - mozilla::DropJSObjects(this); -}; - -void ExtensionEventManager::ReleaseListeners() { - if (mListeners.empty()) { - return; - } - - for (auto iter = mListeners.iter(); !iter.done(); iter.next()) { - iter.get().value()->Cleanup(); - } - - mListeners.clear(); -} - -JSObject* ExtensionEventManager::WrapObject(JSContext* aCx, - JS::Handle aGivenProto) { - return dom::ExtensionEventManager_Binding::Wrap(aCx, this, aGivenProto); -} - -nsIGlobalObject* ExtensionEventManager::GetParentObject() const { - return mGlobal; -} - -void ExtensionEventManager::AddListener( - JSContext* aCx, dom::Function& aCallback, - const dom::Optional>& aOptions, ErrorResult& aRv) { - auto* cb = aCallback.CallbackOrNull(); - if (cb == nullptr) { - ThrowUnexpectedError(aCx, aRv); - return; - } - - RefPtr self = this; - - IgnoredErrorResult rv; - RefPtr wrappedCb = ExtensionEventListener::Create( - mGlobal, &aCallback, - [self = std::move(self)]() { self->ReleaseListeners(); }, rv); - - if (NS_WARN_IF(rv.Failed())) { - ThrowUnexpectedError(aCx, aRv); - return; - } - - RefPtr storedWrapper = wrappedCb; - if (!mListeners.put(cb, std::move(storedWrapper))) { - ThrowUnexpectedError(aCx, aRv); - return; - } - - auto request = SendAddListener(mEventName); - request->Run(mGlobal, aCx, {}, wrappedCb, aRv); -} - -void ExtensionEventManager::RemoveListener(dom::Function& aCallback, - ErrorResult& aRv) { - auto* cb = aCallback.CallbackOrNull(); - const auto& ptr = mListeners.lookup(cb); - - // Return earlier if the listener wasn't found - if (!ptr) { - return; - } - - RefPtr wrappedCb = ptr->value(); - - dom::AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(mGlobal))) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return; - } - - JSContext* cx = jsapi.cx(); - auto request = SendRemoveListener(mEventName); - request->Run(mGlobal, cx, {}, wrappedCb, aRv); - - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - mListeners.remove(cb); - - wrappedCb->Cleanup(); -} - -bool ExtensionEventManager::HasListener(dom::Function& aCallback, - ErrorResult& aRv) const { - return mListeners.has(aCallback.CallbackOrNull()); -} - -bool ExtensionEventManager::HasListeners(ErrorResult& aRv) const { - return !mListeners.empty(); -} - -} // namespace extensions -} // namespace mozilla diff --git a/toolkit/components/extensions/webidl-api/ExtensionEventManager.h b/toolkit/components/extensions/webidl-api/ExtensionEventManager.h deleted file mode 100644 index 50c5583406a3..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionEventManager.h +++ /dev/null @@ -1,93 +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_ExtensionEventManager_h -#define mozilla_extensions_ExtensionEventManager_h - -#include "js/GCHashTable.h" // for JS::GCHashMap -#include "js/TypeDecls.h" // for JS::Handle, JSContext, JSObject, ... -#include "mozilla/Attributes.h" -#include "mozilla/dom/BindingDeclarations.h" -#include "mozilla/ErrorResult.h" -#include "nsCycleCollectionParticipant.h" -#include "nsCOMPtr.h" -#include "nsISupports.h" -#include "nsPointerHashKeys.h" -#include "nsRefPtrHashtable.h" -#include "nsWrapperCache.h" - -#include "ExtensionAPIBase.h" - -class nsIGlobalObject; - -namespace mozilla { - -namespace dom { -class Function; -} // namespace dom - -namespace extensions { - -class ExtensionBrowser; -class ExtensionEventListener; - -class ExtensionEventManager final : public nsISupports, - public nsWrapperCache, - public ExtensionAPIBase { - nsCOMPtr mGlobal; - nsString mAPINamespace; - nsString mEventName; - nsString mAPIObjectType; - nsString mAPIObjectId; - - using ListenerWrappersMap = - JS::GCHashMap, RefPtr, - js::MovableCellHasher>, - js::SystemAllocPolicy>; - - ListenerWrappersMap mListeners; - - ~ExtensionEventManager(); - - void ReleaseListeners(); - - protected: - // ExtensionAPIBase methods - nsIGlobalObject* GetGlobalObject() const override { return mGlobal; } - - nsString GetAPINamespace() const override { return mAPINamespace; } - - nsString GetAPIObjectType() const override { return mAPIObjectType; } - - nsString GetAPIObjectId() const override { return mAPIObjectId; } - - public: - ExtensionEventManager(nsIGlobalObject* aGlobal, const nsAString& aNamespace, - const nsAString& aEventName, - const nsAString& aObjectType = VoidString(), - const nsAString& aObjectId = VoidString()); - - // nsWrapperCache interface methods - JSObject* WrapObject(JSContext* aCx, - JS::Handle aGivenProto) override; - nsIGlobalObject* GetParentObject() const; - - bool HasListener(dom::Function& aCallback, ErrorResult& aRv) const; - bool HasListeners(ErrorResult& aRv) const; - - void AddListener(JSContext* aCx, dom::Function& aCallback, - const dom::Optional>& aOptions, - ErrorResult& aRv); - void RemoveListener(dom::Function& aCallback, ErrorResult& aRv); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionEventManager) -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionEventManager_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionMockAPI.cpp b/toolkit/components/extensions/webidl-api/ExtensionMockAPI.cpp deleted file mode 100644 index b6a892a558de..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionMockAPI.cpp +++ /dev/null @@ -1,113 +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 "ExtensionMockAPI.h" -#include "ExtensionEventManager.h" - -#include "mozilla/dom/ExtensionMockAPIBinding.h" -#include "mozilla/extensions/ExtensionPort.h" -#include "nsIGlobalObject.h" - -namespace mozilla { -namespace extensions { - -NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionMockAPI); -NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionMockAPI) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ExtensionMockAPI, mGlobal, - mOnTestEventMgr); - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionMockAPI) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -ExtensionMockAPI::ExtensionMockAPI(nsIGlobalObject* aGlobal, - ExtensionBrowser* aExtensionBrowser) - : mGlobal(aGlobal) { - MOZ_DIAGNOSTIC_ASSERT(mGlobal); -} - -/* static */ -bool ExtensionMockAPI::IsAllowed(JSContext* aCx, JSObject* aGlobal) { - return true; -} - -JSObject* ExtensionMockAPI::WrapObject(JSContext* aCx, - JS::Handle aGivenProto) { - return dom::ExtensionMockAPI_Binding::Wrap(aCx, this, aGivenProto); -} - -nsIGlobalObject* ExtensionMockAPI::GetParentObject() const { return mGlobal; } - -void ExtensionMockAPI::GetPropertyAsErrorObject( - JSContext* aCx, JS::MutableHandle aRetval) { - IgnoredErrorResult rv; - RefPtr 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) { - 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 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() { - if (!mOnTestEventMgr) { - mOnTestEventMgr = CreateEventManager(u"onTestEvent"_ns); - } - - return mOnTestEventMgr; -} - -already_AddRefed ExtensionMockAPI::CallWebExtMethodReturnsPort( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, ErrorResult& aRv) { - JS::Rooted 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 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 diff --git a/toolkit/components/extensions/webidl-api/ExtensionMockAPI.h b/toolkit/components/extensions/webidl-api/ExtensionMockAPI.h deleted file mode 100644 index b656086a47e8..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionMockAPI.h +++ /dev/null @@ -1,76 +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_ExtensionMockAPI_h -#define mozilla_extensions_ExtensionMockAPI_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 { - -using dom::DOMString; - -class ExtensionEventManager; -class ExtensionPort; - -class ExtensionMockAPI final : public nsISupports, - public nsWrapperCache, - public ExtensionAPINamespace { - nsCOMPtr mGlobal; - RefPtr mOnTestEventMgr; - - ~ExtensionMockAPI() = default; - - protected: - // ExtensionAPIBase methods - nsIGlobalObject* GetGlobalObject() const override { return mGlobal; } - - nsString GetAPINamespace() const override { return u"mockExtensionAPI"_ns; } - - public: - ExtensionMockAPI(nsIGlobalObject* aGlobal, - ExtensionBrowser* aExtensionBrowser); - - // nsWrapperCache interface methods - JSObject* WrapObject(JSContext* aCx, - JS::Handle aGivenProto) override; - - // DOM bindings methods - static bool IsAllowed(JSContext* aCx, JSObject* aGlobal); - - nsIGlobalObject* GetParentObject() const; - - void GetPropertyAsErrorObject(JSContext* aCx, - JS::MutableHandle aRetval); - void GetPropertyAsString(DOMString& aRetval); - - already_AddRefed CallWebExtMethodReturnsPort( - JSContext* aCx, const nsAString& aApiMethod, - const dom::Sequence& aArgs, ErrorResult& aRv); - - ExtensionEventManager* OnTestEvent(); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionMockAPI) -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionMockAPI_h diff --git a/toolkit/components/extensions/webidl-api/ExtensionPort.cpp b/toolkit/components/extensions/webidl-api/ExtensionPort.cpp deleted file mode 100644 index e579c147200b..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionPort.cpp +++ /dev/null @@ -1,89 +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 "ExtensionPort.h" -#include "ExtensionEventManager.h" - -#include "mozilla/dom/BindingUtils.h" // SequenceRooter -#include "mozilla/dom/ExtensionPortBinding.h" -#include "mozilla/dom/ScriptSettings.h" // AutoEntryScript -#include "nsIGlobalObject.h" - -namespace mozilla { -namespace extensions { - -NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionPort); -NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionPort) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ExtensionPort, mGlobal, - mOnDisconnectEventMgr, - mOnMessageEventMgr); - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionPort) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -// static -already_AddRefed ExtensionPort::Create( - nsIGlobalObject* aGlobal, JS::Handle aDescriptorValue, - ErrorResult& aRv) { - if (!aDescriptorValue.isObject()) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - dom::AutoEntryScript aes(&aDescriptorValue.toObject(), __func__); - JSContext* acx = aes.cx(); - auto portDescriptor = MakeUnique(); - if (!portDescriptor->Init(acx, aDescriptorValue, __func__)) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - RefPtr port = - new ExtensionPort(aGlobal, std::move(portDescriptor)); - return port.forget(); -} - -ExtensionPort::ExtensionPort( - nsIGlobalObject* aGlobal, - UniquePtr aPortDescriptor) - : mGlobal(aGlobal), mPortDescriptor(std::move(aPortDescriptor)) { - MOZ_DIAGNOSTIC_ASSERT(mGlobal); -} - -nsString ExtensionPort::GetAPIObjectId() const { - return mPortDescriptor->mPortId; -} - -JSObject* ExtensionPort::WrapObject(JSContext* aCx, - JS::Handle aGivenProto) { - return dom::ExtensionPort_Binding::Wrap(aCx, this, aGivenProto); -} - -nsIGlobalObject* ExtensionPort::GetParentObject() const { return mGlobal; } - -ExtensionEventManager* ExtensionPort::OnMessage() { - if (!mOnMessageEventMgr) { - mOnMessageEventMgr = CreateEventManager(u"onMessage"_ns); - } - - return mOnMessageEventMgr; -} - -ExtensionEventManager* ExtensionPort::OnDisconnect() { - if (!mOnDisconnectEventMgr) { - mOnDisconnectEventMgr = CreateEventManager(u"onDisconnect"_ns); - } - - return mOnDisconnectEventMgr; -} - -void ExtensionPort::GetName(nsAString& aString) { - aString.Assign(mPortDescriptor->mName); -} - -} // namespace extensions -} // namespace mozilla diff --git a/toolkit/components/extensions/webidl-api/ExtensionPort.h b/toolkit/components/extensions/webidl-api/ExtensionPort.h deleted file mode 100644 index 863160849a26..000000000000 --- a/toolkit/components/extensions/webidl-api/ExtensionPort.h +++ /dev/null @@ -1,87 +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_ExtensionPort_h -#define mozilla_extensions_ExtensionPort_h - -#include "js/TypeDecls.h" -#include "mozilla/dom/BindingDeclarations.h" -#include "nsWrapperCache.h" - -#include "ExtensionAPIBase.h" - -class nsIGlobalObject; - -namespace mozilla { - -class ErrorResult; - -namespace dom { -struct ExtensionPortDescriptor; -} - -namespace extensions { - -class ExtensionEventManager; - -class ExtensionPort final : public nsISupports, - public nsWrapperCache, - public ExtensionAPIBase { - nsCOMPtr mGlobal; - RefPtr mOnDisconnectEventMgr; - RefPtr mOnMessageEventMgr; - UniquePtr mPortDescriptor; - - ~ExtensionPort() = default; - ExtensionPort(nsIGlobalObject* aGlobal, - UniquePtr aPortDescriptor); - - protected: - // ExtensionAPIBase methods - nsIGlobalObject* GetGlobalObject() const override { return mGlobal; } - - nsString GetAPINamespace() const override { return u"runtime"_ns; } - - nsString GetAPIObjectType() const override { return u"Port"_ns; } - - nsString GetAPIObjectId() const override; - - public: - static already_AddRefed Create( - nsIGlobalObject* aGlobal, JS::Handle aDescriptorValue, - ErrorResult& aRv); - - // nsWrapperCache interface methods - JSObject* WrapObject(JSContext* aCx, - JS::Handle aGivenProto) override; - - nsIGlobalObject* GetParentObject() const; - - ExtensionEventManager* OnDisconnect(); - ExtensionEventManager* OnMessage(); - - void GetName(nsAString& aString); - void GetError(JSContext* aCx, JS::MutableHandle 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 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 - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionPort) -}; - -} // namespace extensions -} // namespace mozilla - -#endif // mozilla_extensions_ExtensionPort_h diff --git a/toolkit/components/extensions/webidl-api/moz.build b/toolkit/components/extensions/webidl-api/moz.build deleted file mode 100644 index 96899960f4c6..000000000000 --- a/toolkit/components/extensions/webidl-api/moz.build +++ /dev/null @@ -1,46 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -with Files("**"): - BUG_COMPONENT = ("WebExtensions", "General") - -UNIFIED_SOURCES += [ - "ExtensionAPIBase.cpp", - "ExtensionAPIRequest.cpp", - "ExtensionAPIRequestForwarder.cpp", - "ExtensionBrowser.cpp", - "ExtensionEventListener.cpp", - "ExtensionEventManager.cpp", - "ExtensionPort.cpp", -] - -EXPORTS.mozilla.extensions += [ - "ExtensionAPIBase.h", - "ExtensionBrowser.h", - "ExtensionEventManager.h", - "ExtensionPort.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 -# a specific WebExtensions API. -UNIFIED_SOURCES += ["ExtensionMockAPI.cpp"] -EXPORTS.mozilla.extensions += ["ExtensionMockAPI.h"] - -# Propagate the build config to be able to use it in souce code preprocessing -# (used in mozilla::extensions::ExtensionAPIAllowed to disable the webidl -# bindings in non-nightly builds). -if CONFIG["MOZ_WEBEXT_WEBIDL_ENABLED"]: - DEFINES["MOZ_WEBEXT_WEBIDL_ENABLED"] = True - -include("/ipc/chromium/chromium-config.mozbuild") - -LOCAL_INCLUDES += [ - "/js/xpconnect/src", -] - -FINAL_LIBRARY = "xul" diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index de027c19049a..50dff5ecc283 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -300,13 +300,6 @@ this.AppConstants = Object.freeze({ false, #endif - MOZ_WEBEXT_WEBIDL_ENABLED: -#ifdef MOZ_WEBEXT_WEBIDL_ENABLED - true, -#else - false, -#endif - MENUBAR_CAN_AUTOHIDE: #ifdef MENUBAR_CAN_AUTOHIDE true, diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index cc16f498bb67..276d987c2d74 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -301,7 +301,6 @@ for var in ( "MOZ_UNSIGNED_SYSTEM_SCOPE", "MOZ_UPDATE_AGENT", "MOZ_UPDATER", - "MOZ_WEBEXT_WEBIDL_ENABLED", ): if CONFIG[var]: DEFINES[var] = True diff --git a/toolkit/moz.configure b/toolkit/moz.configure index 857499501a75..f74ab261667d 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -1486,31 +1486,6 @@ def addon_sideload_allowed(value): set_config("MOZ_ALLOW_ADDON_SIDELOAD", addon_sideload_allowed) -# WebExtensions API WebIDL bindings -# ============================================================== - - -@depends(milestone) -def extensions_webidl_bindings_default(milestone): - # Only enable the webidl bindings for the WebExtensions APIs - # in Nightly. - return milestone.is_nightly - - -option( - "--enable-extensions-webidl-bindings", - default=extensions_webidl_bindings_default, - help="{Enable|Disable} building experimental WebExtensions WebIDL bindings", -) - - -@depends("--enable-extensions-webidl-bindings") -def extensions_webidl_enabled(value): - return bool(value) - - -set_config("MOZ_WEBEXT_WEBIDL_ENABLED", extensions_webidl_enabled) - # Launcher process (Windows only) # ==============================================================