EventWithOptionsRunnable.cpp (4821B)
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/. */ 6 7 #include "EventWithOptionsRunnable.h" 8 9 #include "MainThreadUtils.h" 10 #include "WorkerScope.h" 11 #include "js/GlobalObject.h" 12 #include "js/RootingAPI.h" 13 #include "js/StructuredClone.h" 14 #include "js/Value.h" 15 #include "mozilla/Assertions.h" 16 #include "mozilla/DOMEventTargetHelper.h" 17 #include "mozilla/ErrorResult.h" 18 #include "mozilla/OwningNonNull.h" 19 #include "mozilla/RefPtr.h" 20 #include "mozilla/dom/Event.h" 21 #include "mozilla/dom/MessagePort.h" 22 #include "mozilla/dom/MessagePortBinding.h" 23 #include "mozilla/dom/StructuredCloneHolder.h" 24 #include "mozilla/dom/WorkerCommon.h" 25 #include "mozilla/dom/WorkerRunnable.h" 26 #include "nsCOMPtr.h" 27 #include "nsContentUtils.h" 28 #include "nsDebug.h" 29 #include "nsGlobalWindowInner.h" 30 #include "nsIGlobalObject.h" 31 #include "nsJSPrincipals.h" 32 #include "xpcpublic.h" 33 34 namespace mozilla::dom { 35 EventWithOptionsRunnable::EventWithOptionsRunnable(Worker& aWorker, 36 const char* aName) 37 : WorkerDebuggeeRunnable(aName), 38 StructuredCloneHolder(CloningSupported, TransferringSupported, 39 StructuredCloneScope::SameProcess) {} 40 41 EventWithOptionsRunnable::~EventWithOptionsRunnable() = default; 42 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()); 47 48 aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable, 49 &transferable); 50 if (NS_WARN_IF(aRv.Failed())) { 51 return; 52 } 53 54 JS::CloneDataPolicy clonePolicy; 55 // DedicatedWorkers are always part of the same agent cluster. 56 clonePolicy.allowIntraClusterClonableSharedObjects(); 57 58 MOZ_ASSERT(NS_IsMainThread()); 59 nsGlobalWindowInner* win = nsContentUtils::IncumbentInnerWindow(); 60 if (win && win->IsSharedMemoryAllowed()) { 61 clonePolicy.allowSharedMemoryObjects(); 62 } 63 64 Write(aCx, aOptions, transferable, clonePolicy, aRv); 65 } 66 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(); 73 74 // For some workers without window, parent is null and we try to find it 75 // from the JS Context. 76 if (!parent) { 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); 81 return false; 82 } 83 84 parent = xpc::NativeGlobal(globalObject); 85 if (NS_WARN_IF(!parent)) { 86 rv.ThrowDataCloneError("failed to get parent"); 87 OptionsDeserializeFailed(rv); 88 return false; 89 } 90 } 91 92 MOZ_ASSERT(parent); 93 94 JS::Rooted<JS::Value> options(aCx); 95 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(); 102 } 103 104 if (aWorkerPrivate->IsSharedMemoryAllowed()) { 105 cloneDataPolicy.allowSharedMemoryObjects(); 106 } 107 108 Read(parent, aCx, &options, cloneDataPolicy, rv); 109 110 if (NS_WARN_IF(rv.Failed())) { 111 OptionsDeserializeFailed(rv); 112 return false; 113 } 114 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); 120 return false; 121 } 122 123 RefPtr<dom::Event> event = BuildEvent(aCx, parent, aTarget, options); 124 125 if (NS_WARN_IF(!event)) { 126 return false; 127 } 128 129 aTarget->DispatchEvent(*event); 130 return true; 131 } 132 133 bool EventWithOptionsRunnable::WorkerRun(JSContext* aCx, 134 WorkerPrivate* aWorkerPrivate) { 135 MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx)); 136 MOZ_ASSERT(aWorkerPrivate->GlobalScope()); 137 138 // If the worker start shutting down, don't dispatch the event. 139 if (NS_FAILED( 140 aWorkerPrivate->GlobalScope()->CheckCurrentGlobalCorrectness())) { 141 return true; 142 } 143 144 return BuildAndFireEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope()); 145 } 146 147 } // namespace mozilla::dom