From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../webidl-api/ExtensionAPIRequestForwarder.h | 258 +++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.h (limited to 'toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.h') diff --git a/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.h b/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.h new file mode 100644 index 0000000000..a74c3e7c45 --- /dev/null +++ b/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.h @@ -0,0 +1,258 @@ +/* -*- 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/SerializedStackHolder.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; +} // 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::Handle 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::MutableHandle aRetVal, ErrorResult& aRv); + + void Run(nsIGlobalObject* aGlobal, JSContext* aCx, + const dom::Sequence& aArgs, + ExtensionEventListener* aListener, + JS::MutableHandle 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::MutableHandle aRetVal, ErrorResult& aRv); + + void SetSerializedCallerStack( + UniquePtr aCallerStack); + + protected: + virtual ~ExtensionAPIRequestForwarder() = default; + + private: + already_AddRefed CreateAPIRequest( + nsIGlobalObject* aGlobal, JSContext* aCx, + const dom::Sequence& aArgs, ExtensionEventListener* aListener, + ErrorResult& aRv); + + APIRequestType mRequestType; + ExtensionAPIRequestTarget mRequestTarget; + Maybe> mStackHolder; +}; + +/* + * 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); + + void SetSerializedCallerStack( + UniquePtr aCallerStack); + + /** + * 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::MutableHandle aResult, + ErrorResult& aRv); + + Maybe GetResultType() { + return mResultType; + } + + protected: + virtual bool ProcessHandlerResult(JSContext* aCx, + JS::MutableHandle aRetval); + + already_AddRefed GetWebExtensionPolicy(); + already_AddRefed CreateAPIRequest(JSContext* aCx); + + void SerializeCallerStack(JSContext* aCx); + void DeserializeCallerStack(JSContext* aCx, + JS::MutableHandle aRetval); + void SerializeArgs(JSContext* aCx, const dom::Sequence& aArgs, + ErrorResult& aRv); + nsresult DeserializeArgs(JSContext* aCx, JS::MutableHandle aArgs); + + bool HandleAPIRequest(JSContext* aCx, JS::MutableHandle aRetval); + + Maybe mResultType; + Maybe> mResultHolder; + RefPtr mPromiseProxy; + Maybe> mArgsHolder; + Maybe> mStackHolder; + Maybe mClientInfo; + uint64_t mSWDescriptorId; + + // 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; +}; + +class RequestInitWorkerRunnable : public dom::WorkerMainThreadRunnable { + Maybe mClientInfo; + + public: + RequestInitWorkerRunnable(dom::WorkerPrivate* aWorkerPrivate, + Maybe& aSWClientInfo); + bool MainThreadRun() override; +}; + +class NotifyWorkerLoadedRunnable : public Runnable { + uint64_t mSWDescriptorId; + nsCOMPtr mSWBaseURI; + + public: + explicit NotifyWorkerLoadedRunnable(const uint64_t aServiceWorkerDescriptorId, + const nsCOMPtr& aWorkerBaseURI) + : Runnable("extensions::NotifyWorkerLoadedRunnable"), + mSWDescriptorId(aServiceWorkerDescriptorId), + mSWBaseURI(aWorkerBaseURI) { + MOZ_ASSERT(mSWDescriptorId > 0); + MOZ_ASSERT(mSWBaseURI); + } + + NS_IMETHOD Run() override; + + NS_INLINE_DECL_REFCOUNTING_INHERITED(NotifyWorkerLoadedRunnable, Runnable) + + private: + ~NotifyWorkerLoadedRunnable() = default; +}; + +class NotifyWorkerDestroyedRunnable : public Runnable { + uint64_t mSWDescriptorId; + nsCOMPtr mSWBaseURI; + + public: + explicit NotifyWorkerDestroyedRunnable( + const uint64_t aServiceWorkerDescriptorId, + const nsCOMPtr& aWorkerBaseURI) + : Runnable("extensions::NotifyWorkerDestroyedRunnable"), + mSWDescriptorId(aServiceWorkerDescriptorId), + mSWBaseURI(aWorkerBaseURI) { + MOZ_ASSERT(mSWDescriptorId > 0); + MOZ_ASSERT(mSWBaseURI); + } + + NS_IMETHOD Run() override; + + NS_INLINE_DECL_REFCOUNTING_INHERITED(NotifyWorkerDestroyedRunnable, Runnable) + + private: + ~NotifyWorkerDestroyedRunnable() = default; +}; + +} // namespace extensions +} // namespace mozilla + +#endif // mozilla_extensions_ExtensionAPIRequestForwarder_h -- cgit v1.2.3