1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #include "EventWithOptionsRunnable.h"
8 #include "WorkerScope.h"
9 #include "mozilla/dom/WorkerRunnable.h"
10 #include "mozilla/dom/StructuredCloneHolder.h"
11 #include "js/StructuredClone.h"
12 #include "js/RootingAPI.h"
14 #include "nsJSPrincipals.h"
15 #include "nsContentUtils.h"
17 #include "MainThreadUtils.h"
18 #include "mozilla/Assertions.h"
19 #include "nsGlobalWindowInner.h"
20 #include "mozilla/DOMEventTargetHelper.h"
21 #include "mozilla/ErrorResult.h"
22 #include "nsIGlobalObject.h"
24 #include "js/GlobalObject.h"
25 #include "xpcpublic.h"
26 #include "mozilla/dom/MessagePortBinding.h"
27 #include "mozilla/dom/MessagePort.h"
28 #include "mozilla/OwningNonNull.h"
29 #include "mozilla/RefPtr.h"
30 #include "mozilla/dom/Event.h"
31 #include "mozilla/dom/WorkerCommon.h"
33 namespace mozilla::dom
{
34 EventWithOptionsRunnable::EventWithOptionsRunnable(Worker
& aWorker
,
36 : WorkerDebuggeeRunnable(aWorker
.mWorkerPrivate
, aName
,
37 WorkerRunnable::WorkerThread
),
38 StructuredCloneHolder(CloningSupported
, TransferringSupported
,
39 StructuredCloneScope::SameProcess
) {}
41 EventWithOptionsRunnable::~EventWithOptionsRunnable() = default;
43 void EventWithOptionsRunnable::InitOptions(
44 JSContext
* aCx
, JS::Handle
<JS::Value
> aOptions
,
45 const Sequence
<JSObject
*>& aTransferable
, ErrorResult
& aRv
) {
46 JS::Rooted
<JS::Value
> transferable(aCx
, JS::UndefinedValue());
48 aRv
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransferable
,
50 if (NS_WARN_IF(aRv
.Failed())) {
54 JS::CloneDataPolicy clonePolicy
;
55 // DedicatedWorkers are always part of the same agent cluster.
56 clonePolicy
.allowIntraClusterClonableSharedObjects();
58 MOZ_ASSERT(NS_IsMainThread());
59 nsGlobalWindowInner
* win
= nsContentUtils::IncumbentInnerWindow();
60 if (win
&& win
->IsSharedMemoryAllowed()) {
61 clonePolicy
.allowSharedMemoryObjects();
64 Write(aCx
, aOptions
, transferable
, clonePolicy
, aRv
);
67 // Cargo-culted from MesssageEventRunnable.
68 bool EventWithOptionsRunnable::BuildAndFireEvent(
69 JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
,
70 DOMEventTargetHelper
* aTarget
) {
71 IgnoredErrorResult rv
;
72 nsCOMPtr
<nsIGlobalObject
> parent
= aTarget
->GetParentObject();
74 // For some workers without window, parent is null and we try to find it
75 // from the JS Context.
77 JS::Rooted
<JSObject
*> globalObject(aCx
, JS::CurrentGlobalOrNull(aCx
));
78 if (NS_WARN_IF(!globalObject
)) {
79 rv
.ThrowDataCloneError("failed to get global object");
80 OptionsDeserializeFailed(rv
);
84 parent
= xpc::NativeGlobal(globalObject
);
85 if (NS_WARN_IF(!parent
)) {
86 rv
.ThrowDataCloneError("failed to get parent");
87 OptionsDeserializeFailed(rv
);
94 JS::Rooted
<JS::Value
> options(aCx
);
96 JS::CloneDataPolicy cloneDataPolicy
;
97 if (parent
->GetClientInfo().isSome() &&
98 parent
->GetClientInfo()->AgentClusterId().isSome() &&
99 parent
->GetClientInfo()->AgentClusterId()->Equals(
100 aWorkerPrivate
->AgentClusterId())) {
101 cloneDataPolicy
.allowIntraClusterClonableSharedObjects();
104 if (aWorkerPrivate
->IsSharedMemoryAllowed()) {
105 cloneDataPolicy
.allowSharedMemoryObjects();
108 Read(parent
, aCx
, &options
, cloneDataPolicy
, rv
);
110 if (NS_WARN_IF(rv
.Failed())) {
111 OptionsDeserializeFailed(rv
);
115 Sequence
<OwningNonNull
<MessagePort
>> ports
;
116 if (NS_WARN_IF(!TakeTransferredPortsAsSequence(ports
))) {
117 // TODO: Is this an appropriate type? What does this actually do?
118 rv
.ThrowDataCloneError("TakeTransferredPortsAsSequence failed");
119 OptionsDeserializeFailed(rv
);
123 RefPtr
<dom::Event
> event
= BuildEvent(aCx
, parent
, aTarget
, options
);
125 if (NS_WARN_IF(!event
)) {
129 aTarget
->DispatchEvent(*event
);
133 bool EventWithOptionsRunnable::WorkerRun(JSContext
* aCx
,
134 WorkerPrivate
* aWorkerPrivate
) {
135 if (mTarget
== ParentThread
) {
136 // Don't fire this event if the JS object has been disconnected from the
138 if (!aWorkerPrivate
->IsAcceptingEvents()) {
142 aWorkerPrivate
->AssertInnerWindowIsCorrect();
144 return BuildAndFireEvent(aCx
, aWorkerPrivate
,
145 aWorkerPrivate
->ParentEventTargetRef());
148 MOZ_ASSERT(aWorkerPrivate
== GetWorkerPrivateFromContext(aCx
));
149 MOZ_ASSERT(aWorkerPrivate
->GlobalScope());
151 // If the worker start shutting down, don't dispatch the event.
153 aWorkerPrivate
->GlobalScope()->CheckCurrentGlobalCorrectness())) {
157 return BuildAndFireEvent(aCx
, aWorkerPrivate
, aWorkerPrivate
->GlobalScope());
160 } // namespace mozilla::dom