diff options
Diffstat (limited to 'dom/workers')
-rw-r--r-- | dom/workers/WorkerPrivate.cpp | 133 | ||||
-rw-r--r-- | dom/workers/WorkerPrivate.h | 3 |
2 files changed, 116 insertions, 20 deletions
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index c2ab4aca3..bd8a33032 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -495,6 +495,82 @@ private: } }; +class ReportCompileErrorRunnable final : public WorkerRunnable +{ +public: + static void + CreateAndDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + RefPtr<ReportCompileErrorRunnable> runnable = + new ReportCompileErrorRunnable(aCx, aWorkerPrivate); + runnable->Dispatch(); + } + +private: + ReportCompileErrorRunnable(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount) + { + aWorkerPrivate->AssertIsOnWorkerThread(); + } + + void + PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override + { + aWorkerPrivate->AssertIsOnWorkerThread(); + + // Dispatch may fail if the worker was canceled, no need to report that as + // an error, so don't call base class PostDispatch. + } + + bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override + { + if (aWorkerPrivate->IsFrozen() || + aWorkerPrivate->IsParentWindowPaused()) { + MOZ_ASSERT(!IsDebuggerRunnable()); + aWorkerPrivate->QueueRunnable(this); + return true; + } + + if (aWorkerPrivate->IsSharedWorker()) { + aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, EmptyString(), + EmptyString(), + EmptyString(), 0, 0, + JSREPORT_ERROR, + /* isErrorEvent */ false); + return true; + } + + if (aWorkerPrivate->IsServiceWorker()) { + RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); + if (swm) { + swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(), + aWorkerPrivate->WorkerName(), + aWorkerPrivate->ScriptURL(), + EmptyString(), EmptyString(), EmptyString(), + 0, 0, JSREPORT_ERROR, JSEXN_ERR); + } + return true; + } + + if (!aWorkerPrivate->IsAcceptingEvents()) { + return true; + } + + RefPtr<Event> event = + Event::Constructor(aWorkerPrivate, NS_LITERAL_STRING("error"), + EventInit()); + event->SetTrusted(true); + + nsEventStatus status = nsEventStatus_eIgnore; + aWorkerPrivate->DispatchDOMEvent(nullptr, event, nullptr, &status); + return true; + } +}; + class CompileScriptRunnable final : public WorkerRunnable { nsString mScriptURL; @@ -538,9 +614,15 @@ private: } // 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. - // + // reported after we return. We want to propagate just JS exceptions, + // because all the other errors are handled when the script is loaded. + // See: https://dom.spec.whatwg.org/#concept-event-fire + if (rv.Failed() && !rv.IsJSException()) { + ReportCompileErrorRunnable::CreateAndDispatch(aCx, aWorkerPrivate); + rv.SuppressException(); + return false; + } + // This is a little dumb, but aCx is in the null compartment here because we // set it up that way in our Run(), since we had not created the global at // that point yet. So we need to enter the compartment of our global, @@ -1171,7 +1253,8 @@ private: if (aWorkerPrivate->IsSharedWorker()) { aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename, mLine, mLineNumber, - mColumnNumber, mFlags); + mColumnNumber, mFlags, + /* isErrorEvent */ true); return true; } @@ -3250,7 +3333,8 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( const nsAString& aLine, uint32_t aLineNumber, uint32_t aColumnNumber, - uint32_t aFlags) + uint32_t aFlags, + bool aIsErrorEvent) { AssertIsOnMainThread(); @@ -3281,31 +3365,42 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( // May be null. nsPIDOMWindowInner* window = sharedWorker->GetOwner(); - RootedDictionary<ErrorEventInit> errorInit(aCx); - errorInit.mBubbles = false; - errorInit.mCancelable = true; - errorInit.mMessage = aMessage; - errorInit.mFilename = aFilename; - errorInit.mLineno = aLineNumber; - errorInit.mColno = aColumnNumber; - - RefPtr<ErrorEvent> errorEvent = - ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"), - errorInit); - if (!errorEvent) { + RefPtr<Event> event; + + if (aIsErrorEvent) { + RootedDictionary<ErrorEventInit> errorInit(aCx); + errorInit.mBubbles = false; + errorInit.mCancelable = true; + errorInit.mMessage = aMessage; + errorInit.mFilename = aFilename; + errorInit.mLineno = aLineNumber; + errorInit.mColno = aColumnNumber; + + event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"), + errorInit); + } else { + event = Event::Constructor(sharedWorker, NS_LITERAL_STRING("error"), + EventInit()); + } + + if (!event) { ThrowAndReport(window, NS_ERROR_UNEXPECTED); continue; } - errorEvent->SetTrusted(true); + event->SetTrusted(true); bool defaultActionEnabled; - nsresult rv = sharedWorker->DispatchEvent(errorEvent, &defaultActionEnabled); + nsresult rv = sharedWorker->DispatchEvent(event, &defaultActionEnabled); if (NS_FAILED(rv)) { ThrowAndReport(window, rv); continue; } + if (!aIsErrorEvent) { + continue; + } + if (defaultActionEnabled) { // Add the owning window to our list so that we will fire an error event // at it later. diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 8008f30e5..465c0f9a3 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -408,7 +408,8 @@ public: const nsAString& aLine, uint32_t aLineNumber, uint32_t aColumnNumber, - uint32_t aFlags); + uint32_t aFlags, + bool aIsErrorEvent); void WorkerScriptLoaded(); |