Source code

Revision control

Copy as Markdown

Other Tools

/* 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 http://mozilla.org/MPL/2.0/. */
#include "RemoteWorkerDebuggerChild.h"
#include "mozilla/dom/MessageEvent.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/workerinternals/ScriptLoader.h"
#include "nsThreadUtils.h"
namespace mozilla::dom {
namespace {
class RemoteDebuggerMessageEventRunnable final : public WorkerDebuggerRunnable {
nsString mMessage;
public:
explicit RemoteDebuggerMessageEventRunnable(const nsAString& aMessage)
: WorkerDebuggerRunnable("RemoteDebuggerMessageEventRunnable"),
mMessage(aMessage) {}
private:
virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
return true;
}
virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) override {}
virtual bool WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate) override {
WorkerDebuggerGlobalScope* globalScope =
aWorkerPrivate->DebuggerGlobalScope();
MOZ_ASSERT(globalScope);
JS::Rooted<JSString*> message(
aCx, JS_NewUCStringCopyN(aCx, mMessage.get(), mMessage.Length()));
if (!message) {
return false;
}
JS::Rooted<JS::Value> data(aCx, JS::StringValue(message));
RefPtr<MessageEvent> event =
new MessageEvent(globalScope, nullptr, nullptr);
event->InitMessageEvent(nullptr, u"message"_ns, CanBubble::eNo,
Cancelable::eYes, data, u""_ns, u""_ns, nullptr,
Sequence<OwningNonNull<MessagePort>>());
event->SetTrusted(true);
globalScope->DispatchEvent(*event);
return true;
}
};
class CompileRemoteDebuggerScriptRunnable final
: public WorkerDebuggerRunnable {
nsString mScriptURL;
const mozilla::Encoding* mDocumentEncoding;
public:
CompileRemoteDebuggerScriptRunnable(
WorkerPrivate* aWorkerPrivate, const nsAString& aScriptURL,
const mozilla::Encoding* aDocumentEncoding)
: WorkerDebuggerRunnable("CompileDebuggerScriptRunnable"),
mScriptURL(aScriptURL),
mDocumentEncoding(aDocumentEncoding) {}
private:
virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
return true;
}
virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) override {}
virtual bool WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate) override {
aWorkerPrivate->AssertIsOnWorkerThread();
WorkerDebuggerGlobalScope* globalScope =
aWorkerPrivate->CreateDebuggerGlobalScope(aCx);
if (!globalScope) {
NS_WARNING("Failed to make global!");
return false;
}
if (NS_WARN_IF(!aWorkerPrivate->EnsureCSPEventListener())) {
return false;
}
JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper());
ErrorResult rv;
JSAutoRealm ar(aCx, global);
workerinternals::LoadMainScript(aWorkerPrivate, nullptr, mScriptURL,
DebuggerScript, rv, mDocumentEncoding);
rv.WouldReportJSException();
// Explicitly ignore NS_BINDING_ABORTED on rv. Or more precisely, still
// return false and don't SetWorkerScriptExecutedSuccessfully() in that
// case, but don't throw anything on aCx. The idea is to not dispatch error
// events if our load is canceled with that error code.
if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) {
rv.SuppressException();
return false;
}
// Make sure to propagate exceptions from rv onto aCx, so that they will get
// reported after we return. We do this for all failures on rv, because now
// we're using rv to track all the state we care about.
if (rv.MaybeSetPendingException(aCx)) {
return false;
}
return true;
}
};
} // namespace
RemoteWorkerDebuggerChild::RemoteWorkerDebuggerChild(
WorkerPrivate* aWorkerPrivate) {
MOZ_ASSERT_DEBUG_OR_FUZZING(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
}
RemoteWorkerDebuggerChild::~RemoteWorkerDebuggerChild() {}
mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvRegisterDone() {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate);
workerPrivate->SetIsRemoteDebuggerRegistered(true);
return IPC_OK();
}
mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvUnregisterDone() {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate);
workerPrivate->SetIsRemoteDebuggerRegistered(false);
return IPC_OK();
}
mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvInitialize(
const nsString& aURL) {
if (!mIsInitialized) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate);
RefPtr<CompileRemoteDebuggerScriptRunnable> runnable =
new CompileRemoteDebuggerScriptRunnable(workerPrivate, aURL, nullptr);
Unused << NS_WARN_IF(!runnable->Dispatch(workerPrivate));
Unused << SendSetAsInitialized();
}
mIsInitialized = true;
return IPC_OK();
}
mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvPostMessage(
const nsString& aMessage) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate);
RefPtr<RemoteDebuggerMessageEventRunnable> runnable =
new RemoteDebuggerMessageEventRunnable(aMessage);
Unused << NS_WARN_IF(!runnable->Dispatch(workerPrivate));
return IPC_OK();
}
mozilla::ipc::IPCResult RemoteWorkerDebuggerChild::RecvSetDebuggerReady(
const bool& aReady) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate);
workerPrivate->SetIsRemoteDebuggerReady(aReady);
return IPC_OK();
}
} // namespace mozilla::dom