/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=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 https://mozilla.org/MPL/2.0/. */ #include "EventWithOptionsRunnable.h" #include "WorkerScope.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/dom/StructuredCloneHolder.h" #include "js/StructuredClone.h" #include "js/RootingAPI.h" #include "js/Value.h" #include "nsJSPrincipals.h" #include "nsContentUtils.h" #include "nsDebug.h" #include "MainThreadUtils.h" #include "mozilla/Assertions.h" #include "nsGlobalWindowInner.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/ErrorResult.h" #include "nsIGlobalObject.h" #include "nsCOMPtr.h" #include "js/GlobalObject.h" #include "xpcpublic.h" #include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/MessagePort.h" #include "mozilla/OwningNonNull.h" #include "mozilla/RefPtr.h" #include "mozilla/dom/Event.h" #include "mozilla/dom/WorkerCommon.h" namespace mozilla::dom { EventWithOptionsRunnable::EventWithOptionsRunnable(Worker& aWorker, const char* aName) : WorkerDebuggeeRunnable(aWorker.mWorkerPrivate, aName, WorkerRunnable::WorkerThread), StructuredCloneHolder(CloningSupported, TransferringSupported, StructuredCloneScope::SameProcess) {} EventWithOptionsRunnable::~EventWithOptionsRunnable() = default; void EventWithOptionsRunnable::InitOptions( JSContext* aCx, JS::Handle aOptions, const Sequence& aTransferable, ErrorResult& aRv) { JS::Rooted transferable(aCx, JS::UndefinedValue()); aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable, &transferable); if (NS_WARN_IF(aRv.Failed())) { return; } JS::CloneDataPolicy clonePolicy; // DedicatedWorkers are always part of the same agent cluster. clonePolicy.allowIntraClusterClonableSharedObjects(); MOZ_ASSERT(NS_IsMainThread()); nsGlobalWindowInner* win = nsContentUtils::IncumbentInnerWindow(); if (win && win->IsSharedMemoryAllowed()) { clonePolicy.allowSharedMemoryObjects(); } Write(aCx, aOptions, transferable, clonePolicy, aRv); } // Cargo-culted from MesssageEventRunnable. bool EventWithOptionsRunnable::BuildAndFireEvent( JSContext* aCx, WorkerPrivate* aWorkerPrivate, DOMEventTargetHelper* aTarget) { IgnoredErrorResult rv; nsCOMPtr parent = aTarget->GetParentObject(); // For some workers without window, parent is null and we try to find it // from the JS Context. if (!parent) { JS::Rooted globalObject(aCx, JS::CurrentGlobalOrNull(aCx)); if (NS_WARN_IF(!globalObject)) { rv.ThrowDataCloneError("failed to get global object"); OptionsDeserializeFailed(rv); return false; } parent = xpc::NativeGlobal(globalObject); if (NS_WARN_IF(!parent)) { rv.ThrowDataCloneError("failed to get parent"); OptionsDeserializeFailed(rv); return false; } } MOZ_ASSERT(parent); JS::Rooted options(aCx); JS::CloneDataPolicy cloneDataPolicy; if (parent->GetClientInfo().isSome() && parent->GetClientInfo()->AgentClusterId().isSome() && parent->GetClientInfo()->AgentClusterId()->Equals( aWorkerPrivate->AgentClusterId())) { cloneDataPolicy.allowIntraClusterClonableSharedObjects(); } if (aWorkerPrivate->IsSharedMemoryAllowed()) { cloneDataPolicy.allowSharedMemoryObjects(); } Read(parent, aCx, &options, cloneDataPolicy, rv); if (NS_WARN_IF(rv.Failed())) { OptionsDeserializeFailed(rv); return false; } Sequence> ports; if (NS_WARN_IF(!TakeTransferredPortsAsSequence(ports))) { // TODO: Is this an appropriate type? What does this actually do? rv.ThrowDataCloneError("TakeTransferredPortsAsSequence failed"); OptionsDeserializeFailed(rv); return false; } RefPtr event = BuildEvent(aCx, parent, aTarget, options); if (NS_WARN_IF(!event)) { return false; } aTarget->DispatchEvent(*event); return true; } bool EventWithOptionsRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { if (mTarget == ParentThread) { // Don't fire this event if the JS object has been disconnected from the // private object. if (!aWorkerPrivate->IsAcceptingEvents()) { return true; } aWorkerPrivate->AssertInnerWindowIsCorrect(); return BuildAndFireEvent(aCx, aWorkerPrivate, aWorkerPrivate->ParentEventTargetRef()); } MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx)); MOZ_ASSERT(aWorkerPrivate->GlobalScope()); // If the worker start shutting down, don't dispatch the event. if (NS_FAILED( aWorkerPrivate->GlobalScope()->CheckCurrentGlobalCorrectness())) { return true; } return BuildAndFireEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope()); } } // namespace mozilla::dom