Files
tubestation/toolkit/components/extensions/webidl-api/ExtensionAPIRequestForwarder.cpp
Eden Chuang feb314e721 Bug 1894231 - P3 Remove WorkerPrivate* in WorkerMainThreadRunnable. r=dom-worker-reviewers,extension-reviewers,smaug,rpl
Remove mWorkerPrivate from WorkerMainThreadRunnable. Instead, using a ThreadSafeWorkerRef to keep Worker alive until the created syncLoop is destroyed.

In general, WorkerMainThreadRunnable::mWorkerPrivate is only used for dispatching the MainThreadStopSyncLoopRunnable back to the Worker thread. Because of the syncLoop, the Worker is supposed to be kept alive until the created syncLoop is destroyed.

RefPtr<ThreadSafeWorkerRef> WorkerMainThreadRunnable::mWorkerRef is introduced to ensure a valid WorkerPrivate during WorkerMainThreadRunnable's execution.

WorkerMainThreadRunnable::mWorkerRef is allocated just before creating a syncLoop in WorkerMainThreadRunnable::Dispatch. And released after the created syncLoop::Run() finishes.

Depends on D212556

Differential Revision: https://phabricator.services.mozilla.com/D212557
2024-06-24 22:20:51 +00:00

711 lines
23 KiB
C++

/* 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 "ExtensionAPIBase.h"
#include "js/Promise.h"
#include "js/PropertyAndElement.h" // JS_GetElement
#include "mozilla/dom/Client.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/ClonedErrorHolder.h"
#include "mozilla/dom/ExtensionBrowserBinding.h"
#include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/WorkerScope.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::Handle<JS::Value> aJSValue,
dom::Sequence<JS::Value>& aResult) {
bool isArray;
JS::Rooted<JSObject*> 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::Rooted<JS::Value> 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<mozIExtensionAPIRequestHandler> sAPIRequestHandler;
MOZ_ASSERT(NS_IsMainThread());
if (MOZ_UNLIKELY(!sAPIRequestHandler)) {
sAPIRequestHandler = do_ImportESModule(
"resource://gre/modules/ExtensionProcessScript.sys.mjs",
"ExtensionAPIRequestHandler");
MOZ_RELEASE_ASSERT(sAPIRequestHandler);
ClearOnShutdown(&sAPIRequestHandler);
}
return *sAPIRequestHandler;
}
void ExtensionAPIRequestForwarder::SetSerializedCallerStack(
UniquePtr<dom::SerializedStackHolder> aCallerStack) {
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
MOZ_ASSERT(mStackHolder.isNothing());
mStackHolder = Some(std::move(aCallerStack));
}
void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx,
const dom::Sequence<JS::Value>& aArgs,
ExtensionEventListener* aListener,
JS::MutableHandle<JS::Value> aRetVal,
ErrorResult& aRv) {
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
dom::WorkerPrivate* workerPrivate = dom::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
RefPtr<RequestWorkerRunnable> runnable =
new RequestWorkerRunnable(workerPrivate, this);
if (mStackHolder.isSome()) {
runnable->SetSerializedCallerStack(mStackHolder.extract());
}
RefPtr<dom::Promise> 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(workerPrivate, 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<JS::Value> 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<JS::Value> 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<JS::Value>& aArgs,
JS::MutableHandle<JS::Value> aRetVal,
ErrorResult& aRv) {
Run(aGlobal, aCx, aArgs, nullptr, aRetVal, aRv);
}
void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx,
const dom::Sequence<JS::Value>& aArgs,
ErrorResult& aRv) {
JS::Rooted<JS::Value> ignoredRetval(aCx);
Run(aGlobal, aCx, aArgs, nullptr, &ignoredRetval, aRv);
}
void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx,
const dom::Sequence<JS::Value>& aArgs,
ExtensionEventListener* aListener,
ErrorResult& aRv) {
MOZ_ASSERT(aListener);
JS::Rooted<JS::Value> ignoredRetval(aCx);
Run(aGlobal, aCx, aArgs, aListener, &ignoredRetval, aRv);
}
void ExtensionAPIRequestForwarder::Run(
nsIGlobalObject* aGlobal, JSContext* aCx,
const dom::Sequence<JS::Value>& aArgs,
const RefPtr<dom::Promise>& aPromiseRetval, ErrorResult& aRv) {
MOZ_ASSERT(aPromiseRetval);
JS::Rooted<JS::Value> promisedRetval(aCx);
Run(aGlobal, aCx, aArgs, &promisedRetval, aRv);
if (aRv.Failed()) {
return;
}
aPromiseRetval->MaybeResolve(promisedRetval);
}
void ExtensionAPIRequestForwarder::Run(nsIGlobalObject* aGlobal, JSContext* aCx,
JS::MutableHandle<JS::Value> 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::Handle<JSObject*> aObj) {
// Try to serialize the object as a CloneErrorHolder, if it fails then
// the object wasn't an error.
IgnoredErrorResult rv;
UniquePtr<dom::ClonedErrorHolder> 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<JS::Value>& aArgs,
ExtensionEventListener* aListener,
ErrorResult& aRv) {
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
dom::WorkerPrivate* workerPrivate = dom::GetCurrentThreadWorkerPrivate();
mSWDescriptorId = workerPrivate->ServiceWorkerID();
auto* workerScope = workerPrivate->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;
}
if (!mStackHolder.isSome()) {
SerializeCallerStack(aCx);
}
mEventListener = aListener;
}
void RequestWorkerRunnable::Init(nsIGlobalObject* aGlobal, JSContext* aCx,
const dom::Sequence<JS::Value>& aArgs,
const RefPtr<dom::Promise>& 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;
}
RefPtr<dom::PromiseWorkerProxy> promiseProxy =
dom::PromiseWorkerProxy::Create(
dom::GetCurrentThreadWorkerPrivate(), aPromiseRetval,
&kExtensionAPIRequestStructuredCloneCallbacks);
if (!promiseProxy) {
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
return;
}
mPromiseProxy = promiseProxy.forget();
}
void RequestWorkerRunnable::SetSerializedCallerStack(
UniquePtr<dom::SerializedStackHolder> aCallerStack) {
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
MOZ_ASSERT(mStackHolder.isNothing());
mStackHolder = Some(std::move(aCallerStack));
}
void RequestWorkerRunnable::SerializeCallerStack(JSContext* aCx) {
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
MOZ_ASSERT(mStackHolder.isNothing());
mStackHolder = Some(dom::GetCurrentStack(aCx));
}
void RequestWorkerRunnable::DeserializeCallerStack(
JSContext* aCx, JS::MutableHandle<JS::Value> aRetval) {
MOZ_ASSERT(NS_IsMainThread());
if (mStackHolder.isSome()) {
JS::Rooted<JSObject*> savedFrame(aCx, mStackHolder->get()->ReadStack(aCx));
MOZ_ASSERT(savedFrame);
aRetval.set(JS::ObjectValue(*savedFrame));
mStackHolder = Nothing();
}
}
void RequestWorkerRunnable::SerializeArgs(JSContext* aCx,
const dom::Sequence<JS::Value>& aArgs,
ErrorResult& aRv) {
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
MOZ_ASSERT(!mArgsHolder);
JS::Rooted<JS::Value> jsval(aCx);
if (NS_WARN_IF(!ToJSValue(aCx, aArgs, &jsval))) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
mArgsHolder = Some(MakeUnique<dom::StructuredCloneHolder>(
dom::StructuredCloneHolder::CloningSupported,
dom::StructuredCloneHolder::TransferringNotSupported,
JS::StructuredCloneScope::SameProcess));
mArgsHolder->get()->Write(aCx, jsval, aRv);
}
nsresult RequestWorkerRunnable::DeserializeArgs(
JSContext* aCx, JS::MutableHandle<JS::Value> aArgs) {
MOZ_ASSERT(NS_IsMainThread());
if (mArgsHolder.isSome() && mArgsHolder->get()->HasData()) {
IgnoredErrorResult rv;
JS::Rooted<JS::Value> 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<mozIExtensionAPIRequestHandler> handler =
&ExtensionAPIRequestForwarder::APIRequestHandler();
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(handler);
dom::AutoJSAPI jsapi;
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
return false;
}
auto* cx = jsapi.cx();
JS::Rooted<JS::Value> retval(cx);
return HandleAPIRequest(cx, &retval);
}
already_AddRefed<ExtensionAPIRequest> RequestWorkerRunnable::CreateAPIRequest(
JSContext* aCx) {
JS::Rooted<JS::Value> callArgs(aCx);
JS::Rooted<JS::Value> callerStackValue(aCx);
DeserializeArgs(aCx, &callArgs);
DeserializeCallerStack(aCx, &callerStackValue);
RefPtr<ExtensionAPIRequest> request = new ExtensionAPIRequest(
mOuterRequest->GetRequestType(), *mOuterRequest->GetRequestTarget());
request->Init(mClientInfo, mSWDescriptorId, callArgs, callerStackValue);
if (mEventListener) {
request->SetEventListener(mEventListener.forget());
}
return request.forget();
}
already_AddRefed<WebExtensionPolicy>
RequestWorkerRunnable::GetWebExtensionPolicy() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mWorkerRef);
auto* baseURI = mWorkerRef->Private()->GetBaseURI();
RefPtr<WebExtensionPolicy> policy =
ExtensionPolicyService::GetSingleton().GetByURL(baseURI);
return policy.forget();
}
bool RequestWorkerRunnable::HandleAPIRequest(
JSContext* aCx, JS::MutableHandle<JS::Value> aRetval) {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<WebExtensionPolicy> 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<ExtensionAPIRequest> request = CreateAPIRequest(aCx);
nsCOMPtr<mozIExtensionAPIRequestHandler> handler =
&ExtensionAPIRequestForwarder::APIRequestHandler();
RefPtr<mozIExtensionAPIRequestResult> 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<JSObject*> errObj(aCx, &aRetval.toObject());
IgnoredErrorResult rv;
UniquePtr<dom::ClonedErrorHolder> ceh =
dom::ClonedErrorHolder::Create(aCx, errObj, rv);
if (!rv.Failed() && ceh) {
okSerializedError = ToJSValue(aCx, std::move(ceh), aRetval);
} 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::MutableHandle<JS::Value> 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<JSObject*> obj(aCx, &aRetval.toObject());
if (NS_WARN_IF(!JS::IsPromiseObject(obj))) {
return false;
}
ErrorResult rv;
nsIGlobalObject* glob = xpc::CurrentNativeGlobal(aCx);
RefPtr<dom::Promise> retPromise =
dom::Promise::Resolve(glob, aCx, aRetval, rv);
if (rv.Failed()) {
return false;
}
retPromise->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>(
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::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) {
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
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::Rooted<JS::Value> 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);
}
// RequestInitWorkerContextRunnable
RequestInitWorkerRunnable::RequestInitWorkerRunnable(
dom::WorkerPrivate* aWorkerPrivate, Maybe<dom::ClientInfo>& aSWClientInfo)
: WorkerMainThreadRunnable(aWorkerPrivate,
"extensions::RequestInitWorkerRunnable"_ns) {
MOZ_ASSERT(dom::IsCurrentThreadRunningWorker());
MOZ_ASSERT(aSWClientInfo.isSome());
mClientInfo = aSWClientInfo;
}
bool RequestInitWorkerRunnable::MainThreadRun() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mWorkerRef);
dom::WorkerPrivate* workerPrivate = mWorkerRef->Private();
auto* baseURI = workerPrivate->GetBaseURI();
RefPtr<WebExtensionPolicy> policy =
ExtensionPolicyService::GetSingleton().GetByURL(baseURI);
RefPtr<ExtensionServiceWorkerInfo> swInfo = new ExtensionServiceWorkerInfo(
*mClientInfo, workerPrivate->ServiceWorkerID());
nsCOMPtr<mozIExtensionAPIRequestHandler> handler =
&ExtensionAPIRequestForwarder::APIRequestHandler();
MOZ_ASSERT(handler);
if (NS_FAILED(handler->InitExtensionWorker(policy, swInfo))) {
NS_WARNING("nsIExtensionAPIRequestHandler.initExtensionWorker call failed");
}
return true;
}
// NotifyWorkerLoadedRunnable
nsresult NotifyWorkerLoadedRunnable::Run() {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<WebExtensionPolicy> policy =
ExtensionPolicyService::GetSingleton().GetByURL(mSWBaseURI.get());
nsCOMPtr<mozIExtensionAPIRequestHandler> handler =
&ExtensionAPIRequestForwarder::APIRequestHandler();
MOZ_ASSERT(handler);
if (NS_FAILED(handler->OnExtensionWorkerLoaded(policy, mSWDescriptorId))) {
NS_WARNING(
"nsIExtensionAPIRequestHandler.onExtensionWorkerLoaded call failed");
}
return NS_OK;
}
// NotifyWorkerDestroyedRunnable
nsresult NotifyWorkerDestroyedRunnable::Run() {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<WebExtensionPolicy> policy =
ExtensionPolicyService::GetSingleton().GetByURL(mSWBaseURI.get());
nsCOMPtr<mozIExtensionAPIRequestHandler> handler =
&ExtensionAPIRequestForwarder::APIRequestHandler();
MOZ_ASSERT(handler);
if (NS_FAILED(handler->OnExtensionWorkerDestroyed(policy, mSWDescriptorId))) {
NS_WARNING(
"nsIExtensionAPIRequestHandler.onExtensionWorkerDestroyed call failed");
}
return NS_OK;
}
} // namespace extensions
} // namespace mozilla