RemoteWorkerDebuggerChild.cpp (6129B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "RemoteWorkerDebuggerChild.h" 6 7 #include "mozilla/dom/MessageEvent.h" 8 #include "mozilla/dom/MessageEventBinding.h" 9 #include "mozilla/dom/WorkerCommon.h" 10 #include "mozilla/dom/WorkerPrivate.h" 11 #include "mozilla/dom/WorkerRunnable.h" 12 #include "mozilla/dom/WorkerScope.h" 13 #include "mozilla/dom/workerinternals/ScriptLoader.h" 14 #include "nsThreadUtils.h" 15 16 namespace mozilla::dom { 17 18 namespace { 19 20 class RemoteDebuggerMessageEventRunnable final : public WorkerDebuggerRunnable { 21 nsString mMessage; 22 23 public: 24 explicit RemoteDebuggerMessageEventRunnable(const nsAString& aMessage) 25 : WorkerDebuggerRunnable("RemoteDebuggerMessageEventRunnable"), 26 mMessage(aMessage) {} 27 28 private: 29 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { 30 return true; 31 } 32 33 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 34 bool aDispatchResult) override {} 35 36 virtual bool WorkerRun(JSContext* aCx, 37 WorkerPrivate* aWorkerPrivate) override { 38 WorkerDebuggerGlobalScope* globalScope = 39 aWorkerPrivate->DebuggerGlobalScope(); 40 MOZ_ASSERT(globalScope); 41 42 JS::Rooted<JSString*> message( 43 aCx, JS_NewUCStringCopyN(aCx, mMessage.get(), mMessage.Length())); 44 if (!message) { 45 return false; 46 } 47 JS::Rooted<JS::Value> data(aCx, JS::StringValue(message)); 48 49 RefPtr<MessageEvent> event = 50 new MessageEvent(globalScope, nullptr, nullptr); 51 event->InitMessageEvent(nullptr, u"message"_ns, CanBubble::eNo, 52 Cancelable::eYes, data, u""_ns, u""_ns, nullptr, 53 Sequence<OwningNonNull<MessagePort>>()); 54 event->SetTrusted(true); 55 56 globalScope->DispatchEvent(*event); 57 return true; 58 } 59 }; 60 61 class CompileRemoteDebuggerScriptRunnable final 62 : public WorkerDebuggerRunnable { 63 nsString mScriptURL; 64 const mozilla::Encoding* mDocumentEncoding; 65 66 public: 67 CompileRemoteDebuggerScriptRunnable( 68 WorkerPrivate* aWorkerPrivate, const nsAString& aScriptURL, 69 const mozilla::Encoding* aDocumentEncoding) 70 : WorkerDebuggerRunnable("CompileDebuggerScriptRunnable"), 71 mScriptURL(aScriptURL), 72 mDocumentEncoding(aDocumentEncoding) {} 73 74 private: 75 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { 76 return true; 77 } 78 79 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 80 bool aDispatchResult) override {} 81 82 virtual bool WorkerRun(JSContext* aCx, 83 WorkerPrivate* aWorkerPrivate) override { 84 aWorkerPrivate->AssertIsOnWorkerThread(); 85 86 WorkerDebuggerGlobalScope* globalScope = 87 aWorkerPrivate->CreateDebuggerGlobalScope(aCx); 88 if (!globalScope) { 89 NS_WARNING("Failed to make global!"); 90 return false; 91 } 92 93 if (NS_WARN_IF(!aWorkerPrivate->EnsureCSPEventListener())) { 94 return false; 95 } 96 97 JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper()); 98 99 ErrorResult rv; 100 JSAutoRealm ar(aCx, global); 101 workerinternals::LoadMainScript(aWorkerPrivate, nullptr, mScriptURL, 102 DebuggerScript, rv, mDocumentEncoding); 103 rv.WouldReportJSException(); 104 // Explicitly ignore NS_BINDING_ABORTED on rv. Or more precisely, still 105 // return false and don't SetWorkerScriptExecutedSuccessfully() in that 106 // case, but don't throw anything on aCx. The idea is to not dispatch error 107 // events if our load is canceled with that error code. 108 if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) { 109 rv.SuppressException(); 110 return false; 111 } 112 // Make sure to propagate exceptions from rv onto aCx, so that they will get 113 // reported after we return. We do this for all failures on rv, because now 114 // we're using rv to track all the state we care about. 115 if (rv.MaybeSetPendingException(aCx)) { 116 return false; 117 } 118 119 return true; 120 } 121 }; 122 123 } // namespace 124 125 RemoteWorkerDebuggerChild::RemoteWorkerDebuggerChild( 126 WorkerPrivate* aWorkerPrivate) { 127 MOZ_ASSERT_DEBUG_OR_FUZZING(aWorkerPrivate); 128 aWorkerPrivate->AssertIsOnWorkerThread(); 129 } 130 131 RemoteWorkerDebuggerChild::~RemoteWorkerDebuggerChild() {} 132 133 mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvRegisterDone() { 134 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 135 MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate); 136 137 workerPrivate->SetIsRemoteDebuggerRegistered(true); 138 return IPC_OK(); 139 } 140 141 mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvUnregisterDone() { 142 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 143 MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate); 144 145 workerPrivate->SetIsRemoteDebuggerRegistered(false); 146 return IPC_OK(); 147 } 148 149 mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvInitialize( 150 const nsString& aURL) { 151 if (!mIsInitialized) { 152 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 153 MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate); 154 RefPtr<CompileRemoteDebuggerScriptRunnable> runnable = 155 new CompileRemoteDebuggerScriptRunnable(workerPrivate, aURL, nullptr); 156 (void)NS_WARN_IF(!runnable->Dispatch(workerPrivate)); 157 (void)SendSetAsInitialized(); 158 } 159 mIsInitialized = true; 160 return IPC_OK(); 161 } 162 163 mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvPostMessage( 164 const nsString& aMessage) { 165 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 166 MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate); 167 RefPtr<RemoteDebuggerMessageEventRunnable> runnable = 168 new RemoteDebuggerMessageEventRunnable(aMessage); 169 (void)NS_WARN_IF(!runnable->Dispatch(workerPrivate)); 170 return IPC_OK(); 171 } 172 173 mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvSetDebuggerReady( 174 const bool& aReady) { 175 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 176 MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate); 177 workerPrivate->SetIsRemoteDebuggerReady(aReady); 178 return IPC_OK(); 179 } 180 181 } // namespace mozilla::dom