зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1288768 - Better error reporting for network errors in workers, r=bz
This commit is contained in:
Родитель
fed1d780de
Коммит
e14c51cdfd
|
@ -402,8 +402,17 @@ Event::Constructor(const GlobalObject& aGlobal,
|
|||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
RefPtr<Event> e = new Event(t, nullptr, nullptr);
|
||||
bool trusted = e->Init(t);
|
||||
return Constructor(t, aType, aParam);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<Event>
|
||||
Event::Constructor(EventTarget* aEventTarget,
|
||||
const nsAString& aType,
|
||||
const EventInit& aParam)
|
||||
{
|
||||
RefPtr<Event> e = new Event(aEventTarget, nullptr, nullptr);
|
||||
bool trusted = e->Init(aEventTarget);
|
||||
e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
|
||||
e->SetTrusted(trusted);
|
||||
e->SetComposed(aParam.mComposed);
|
||||
|
@ -1207,7 +1216,7 @@ Event::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
Event::SetOwner(mozilla::dom::EventTarget* aOwner)
|
||||
Event::SetOwner(EventTarget* aOwner)
|
||||
{
|
||||
mOwner = nullptr;
|
||||
|
||||
|
|
|
@ -142,6 +142,10 @@ public:
|
|||
LayoutDeviceIntPoint aPoint,
|
||||
CSSIntPoint aDefaultPoint);
|
||||
|
||||
static already_AddRefed<Event> Constructor(EventTarget* aEventTarget,
|
||||
const nsAString& aType,
|
||||
const EventInit& aParam);
|
||||
|
||||
static already_AddRefed<Event> Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const EventInit& aParam,
|
||||
|
|
|
@ -494,6 +494,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;
|
||||
|
@ -537,9 +613,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,
|
||||
|
@ -1117,7 +1199,8 @@ private:
|
|||
if (aWorkerPrivate->IsSharedWorker()) {
|
||||
aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename,
|
||||
mLine, mLineNumber,
|
||||
mColumnNumber, mFlags);
|
||||
mColumnNumber, mFlags,
|
||||
/* isErrorEvent */ true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3291,7 +3374,8 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
|
|||
const nsAString& aLine,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
uint32_t aFlags)
|
||||
uint32_t aFlags,
|
||||
bool aIsErrorEvent)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
|
@ -3322,31 +3406,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<Event> event;
|
||||
|
||||
RefPtr<ErrorEvent> errorEvent =
|
||||
ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
|
||||
errorInit);
|
||||
if (!errorEvent) {
|
||||
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.
|
||||
|
|
|
@ -403,7 +403,8 @@ public:
|
|||
const nsAString& aLine,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
uint32_t aFlags);
|
||||
uint32_t aFlags,
|
||||
bool aIsErrorEvent);
|
||||
|
||||
void
|
||||
WorkerScriptLoaded();
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[worker.html]
|
||||
type: testharness
|
||||
expected: ERROR
|
Загрузка…
Ссылка в новой задаче