MessageEventRunnable.cpp (6458B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=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 http://mozilla.org/MPL/2.0/. */ 6 7 #include "MessageEventRunnable.h" 8 9 #include "WorkerScope.h" 10 #include "mozilla/dom/MessageEvent.h" 11 #include "mozilla/dom/MessageEventBinding.h" 12 #include "mozilla/dom/RootedDictionary.h" 13 #include "nsQueryObject.h" 14 15 namespace mozilla::dom { 16 17 MessageEventRunnable::MessageEventRunnable(WorkerPrivate* aWorkerPrivate) 18 : WorkerDebuggeeRunnable("MessageEventRunnable"), 19 StructuredCloneHolder(CloningSupported, TransferringSupported, 20 StructuredCloneScope::SameProcess) {} 21 22 bool MessageEventRunnable::DispatchDOMEvent(JSContext* aCx, 23 WorkerPrivate* aWorkerPrivate, 24 DOMEventTargetHelper* aTarget, 25 bool aIsMainThread) { 26 nsCOMPtr<nsIGlobalObject> parent = aTarget->GetParentObject(); 27 28 // For some workers without window, parent is null and we try to find it 29 // from the JS Context. 30 if (!parent) { 31 JS::Rooted<JSObject*> globalObject(aCx, JS::CurrentGlobalOrNull(aCx)); 32 if (NS_WARN_IF(!globalObject)) { 33 return false; 34 } 35 36 parent = xpc::NativeGlobal(globalObject); 37 if (NS_WARN_IF(!parent)) { 38 return false; 39 } 40 } 41 42 MOZ_ASSERT(parent); 43 44 JS::Rooted<JS::Value> messageData(aCx); 45 IgnoredErrorResult rv; 46 47 JS::CloneDataPolicy cloneDataPolicy; 48 if (parent->GetClientInfo().isSome() && 49 parent->GetClientInfo()->AgentClusterId().isSome() && 50 parent->GetClientInfo()->AgentClusterId()->Equals( 51 aWorkerPrivate->AgentClusterId())) { 52 cloneDataPolicy.allowIntraClusterClonableSharedObjects(); 53 } 54 55 if (aWorkerPrivate->IsSharedMemoryAllowed()) { 56 cloneDataPolicy.allowSharedMemoryObjects(); 57 } 58 59 Read(parent, aCx, &messageData, cloneDataPolicy, rv); 60 61 if (NS_WARN_IF(rv.Failed())) { 62 DispatchError(aCx, aTarget); 63 return false; 64 } 65 66 Sequence<OwningNonNull<MessagePort>> ports; 67 if (!TakeTransferredPortsAsSequence(ports)) { 68 DispatchError(aCx, aTarget); 69 return false; 70 } 71 72 RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr); 73 event->InitMessageEvent(nullptr, u"message"_ns, CanBubble::eNo, 74 Cancelable::eNo, messageData, u""_ns, u""_ns, nullptr, 75 ports); 76 77 event->SetTrusted(true); 78 79 aTarget->DispatchEvent(*event); 80 81 return true; 82 } 83 84 bool MessageEventRunnable::WorkerRun(JSContext* aCx, 85 WorkerPrivate* aWorkerPrivate) { 86 MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx)); 87 MOZ_ASSERT(aWorkerPrivate->GlobalScope()); 88 89 // If the worker start shutting down, don't dispatch the message event. 90 if (NS_FAILED( 91 aWorkerPrivate->GlobalScope()->CheckCurrentGlobalCorrectness())) { 92 return true; 93 } 94 95 return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(), 96 false); 97 } 98 99 void MessageEventRunnable::DispatchError(JSContext* aCx, 100 DOMEventTargetHelper* aTarget) { 101 RootedDictionary<MessageEventInit> init(aCx); 102 init.mBubbles = false; 103 init.mCancelable = false; 104 105 RefPtr<Event> event = 106 MessageEvent::Constructor(aTarget, u"messageerror"_ns, init); 107 event->SetTrusted(true); 108 109 aTarget->DispatchEvent(*event); 110 } 111 112 MessageEventToParentRunnable::MessageEventToParentRunnable( 113 WorkerPrivate* aWorkerPrivate) 114 : WorkerParentDebuggeeRunnable("MessageEventToParentRunnable"), 115 StructuredCloneHolder(CloningSupported, TransferringSupported, 116 StructuredCloneScope::SameProcess) {} 117 118 bool MessageEventToParentRunnable::DispatchDOMEvent( 119 JSContext* aCx, WorkerPrivate* aWorkerPrivate, 120 DOMEventTargetHelper* aTarget, bool aIsMainThread) { 121 nsCOMPtr<nsIGlobalObject> parent = aTarget->GetParentObject(); 122 123 // For some workers without window, parent is null and we try to find it 124 // from the JS Context. 125 if (!parent) { 126 JS::Rooted<JSObject*> globalObject(aCx, JS::CurrentGlobalOrNull(aCx)); 127 if (NS_WARN_IF(!globalObject)) { 128 return false; 129 } 130 131 parent = xpc::NativeGlobal(globalObject); 132 if (NS_WARN_IF(!parent)) { 133 return false; 134 } 135 } 136 137 MOZ_ASSERT(parent); 138 139 JS::Rooted<JS::Value> messageData(aCx); 140 IgnoredErrorResult rv; 141 142 JS::CloneDataPolicy cloneDataPolicy; 143 if (parent->GetClientInfo().isSome() && 144 parent->GetClientInfo()->AgentClusterId().isSome() && 145 parent->GetClientInfo()->AgentClusterId()->Equals( 146 aWorkerPrivate->AgentClusterId())) { 147 cloneDataPolicy.allowIntraClusterClonableSharedObjects(); 148 } 149 150 if (aWorkerPrivate->IsSharedMemoryAllowed()) { 151 cloneDataPolicy.allowSharedMemoryObjects(); 152 } 153 154 Read(parent, aCx, &messageData, cloneDataPolicy, rv); 155 156 if (NS_WARN_IF(rv.Failed())) { 157 DispatchError(aCx, aTarget); 158 return false; 159 } 160 161 Sequence<OwningNonNull<MessagePort>> ports; 162 if (!TakeTransferredPortsAsSequence(ports)) { 163 DispatchError(aCx, aTarget); 164 return false; 165 } 166 167 RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr); 168 event->InitMessageEvent(nullptr, u"message"_ns, CanBubble::eNo, 169 Cancelable::eNo, messageData, u""_ns, u""_ns, nullptr, 170 ports); 171 172 event->SetTrusted(true); 173 174 aTarget->DispatchEvent(*event); 175 176 return true; 177 } 178 179 bool MessageEventToParentRunnable::WorkerRun(JSContext* aCx, 180 WorkerPrivate* aWorkerPrivate) { 181 if (!aWorkerPrivate->IsAcceptingEvents()) { 182 return true; 183 } 184 185 aWorkerPrivate->AssertInnerWindowIsCorrect(); 186 187 return DispatchDOMEvent(aCx, aWorkerPrivate, 188 aWorkerPrivate->ParentEventTargetRef(), 189 !aWorkerPrivate->GetParent()); 190 } 191 192 void MessageEventToParentRunnable::DispatchError( 193 JSContext* aCx, DOMEventTargetHelper* aTarget) { 194 RootedDictionary<MessageEventInit> init(aCx); 195 init.mBubbles = false; 196 init.mCancelable = false; 197 198 RefPtr<Event> event = 199 MessageEvent::Constructor(aTarget, u"messageerror"_ns, init); 200 event->SetTrusted(true); 201 202 aTarget->DispatchEvent(*event); 203 } 204 205 } // namespace mozilla::dom