258 lines
9.3 KiB
C++
258 lines
9.3 KiB
C++
/* -*- 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<JS::Value> aJSValue,
|
|
dom::Sequence<JS::Value>& 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<JS::Value>& aArgs, ErrorResult& aRv);
|
|
|
|
void Run(nsIGlobalObject* aGlobal, JSContext* aCx,
|
|
const dom::Sequence<JS::Value>& aArgs,
|
|
ExtensionEventListener* aListener, ErrorResult& aRv);
|
|
|
|
void Run(nsIGlobalObject* aGlobal, JSContext* aCx,
|
|
const dom::Sequence<JS::Value>& aArgs,
|
|
JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv);
|
|
|
|
void Run(nsIGlobalObject* aGlobal, JSContext* aCx,
|
|
const dom::Sequence<JS::Value>& aArgs,
|
|
ExtensionEventListener* aListener,
|
|
JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv);
|
|
|
|
void Run(nsIGlobalObject* aGlobal, JSContext* aCx,
|
|
const dom::Sequence<JS::Value>& aArgs,
|
|
const RefPtr<dom::Promise>& aPromiseRetval, ErrorResult& aRv);
|
|
|
|
void Run(nsIGlobalObject* aGlobal, JSContext* aCx,
|
|
JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv);
|
|
|
|
void SetSerializedCallerStack(
|
|
UniquePtr<dom::SerializedStackHolder> aCallerStack);
|
|
|
|
protected:
|
|
virtual ~ExtensionAPIRequestForwarder() = default;
|
|
|
|
private:
|
|
already_AddRefed<ExtensionAPIRequest> CreateAPIRequest(
|
|
nsIGlobalObject* aGlobal, JSContext* aCx,
|
|
const dom::Sequence<JS::Value>& aArgs, ExtensionEventListener* aListener,
|
|
ErrorResult& aRv);
|
|
|
|
APIRequestType mRequestType;
|
|
ExtensionAPIRequestTarget mRequestTarget;
|
|
Maybe<UniquePtr<dom::SerializedStackHolder>> 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<dom::SerializedStackHolder> 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<JS::Value>& 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<JS::Value>& 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<JS::Value>& aArgs,
|
|
const RefPtr<dom::Promise>& aPromiseRetval, ErrorResult& aRv);
|
|
|
|
bool MainThreadRun() override;
|
|
|
|
void ReadResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
|
ErrorResult& aRv);
|
|
|
|
Maybe<mozIExtensionAPIRequestResult::ResultType> GetResultType() {
|
|
return mResultType;
|
|
}
|
|
|
|
protected:
|
|
virtual bool ProcessHandlerResult(JSContext* aCx,
|
|
JS::MutableHandle<JS::Value> aRetval);
|
|
|
|
already_AddRefed<WebExtensionPolicy> GetWebExtensionPolicy();
|
|
already_AddRefed<ExtensionAPIRequest> CreateAPIRequest(JSContext* aCx);
|
|
|
|
void SerializeCallerStack(JSContext* aCx);
|
|
void DeserializeCallerStack(JSContext* aCx,
|
|
JS::MutableHandle<JS::Value> aRetval);
|
|
void SerializeArgs(JSContext* aCx, const dom::Sequence<JS::Value>& aArgs,
|
|
ErrorResult& aRv);
|
|
nsresult DeserializeArgs(JSContext* aCx, JS::MutableHandle<JS::Value> aArgs);
|
|
|
|
bool HandleAPIRequest(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
|
|
|
|
Maybe<mozIExtensionAPIRequestResult::ResultType> mResultType;
|
|
Maybe<UniquePtr<dom::StructuredCloneHolder>> mResultHolder;
|
|
RefPtr<dom::PromiseWorkerProxy> mPromiseProxy;
|
|
Maybe<UniquePtr<dom::StructuredCloneHolder>> mArgsHolder;
|
|
Maybe<UniquePtr<dom::SerializedStackHolder>> mStackHolder;
|
|
Maybe<dom::ClientInfo> mClientInfo;
|
|
uint64_t mSWDescriptorId;
|
|
|
|
// Only set for addListener/removeListener API requests.
|
|
RefPtr<ExtensionEventListener> 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<dom::ClientInfo> mClientInfo;
|
|
|
|
public:
|
|
RequestInitWorkerRunnable(dom::WorkerPrivate* aWorkerPrivate,
|
|
Maybe<dom::ClientInfo>& aSWClientInfo);
|
|
bool MainThreadRun() override;
|
|
};
|
|
|
|
class NotifyWorkerLoadedRunnable : public Runnable {
|
|
uint64_t mSWDescriptorId;
|
|
nsCOMPtr<nsIURI> mSWBaseURI;
|
|
|
|
public:
|
|
explicit NotifyWorkerLoadedRunnable(const uint64_t aServiceWorkerDescriptorId,
|
|
const nsCOMPtr<nsIURI>& 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<nsIURI> mSWBaseURI;
|
|
|
|
public:
|
|
explicit NotifyWorkerDestroyedRunnable(
|
|
const uint64_t aServiceWorkerDescriptorId,
|
|
const nsCOMPtr<nsIURI>& 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
|