mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Bug 1225470 Report a message to the console when a service worker waitUntil() is rejected. r=baku
This commit is contained in:
parent
5855a7439f
commit
60dc9e2371
@ -495,6 +495,7 @@ DOMInterfaces = {
|
||||
'ExtendableEvent': {
|
||||
'headerFile': 'mozilla/dom/ServiceWorkerEvents.h',
|
||||
'nativeType': 'mozilla::dom::workers::ExtendableEvent',
|
||||
'implicitJSContext': [ 'waitUntil' ],
|
||||
},
|
||||
|
||||
'ExtendableMessageEvent': {
|
||||
|
@ -697,7 +697,9 @@ FetchEvent::RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv)
|
||||
spec, line, column);
|
||||
aArg.AppendNativeHandler(handler);
|
||||
|
||||
WaitUntil(aArg, aRv);
|
||||
// Append directly to the lifecycle promises array. Don't call WaitUntil()
|
||||
// because that will lead to double-reporting any errors.
|
||||
mPromises.AppendElement(&aArg);
|
||||
}
|
||||
|
||||
void
|
||||
@ -739,6 +741,94 @@ FetchEvent::ReportCanceled()
|
||||
NS_LITERAL_CSTRING("InterceptionCanceledWithURL"), &requestURL);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class WaitUntilHandler final : public PromiseNativeHandler
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
const nsCString mScope;
|
||||
nsCString mSourceSpec;
|
||||
uint32_t mLine;
|
||||
uint32_t mColumn;
|
||||
nsString mRejectValue;
|
||||
|
||||
~WaitUntilHandler()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
WaitUntilHandler(WorkerPrivate* aWorkerPrivate, JSContext* aCx)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
, mScope(mWorkerPrivate->WorkerName())
|
||||
, mLine(0)
|
||||
, mColumn(0)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// Save the location of the waitUntil() call itself as a fallback
|
||||
// in case the rejection value does not contain any location info.
|
||||
nsJSUtils::GetCallingLocation(aCx, mSourceSpec, &mLine, &mColumn);
|
||||
}
|
||||
|
||||
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
// do nothing, we are only here to report errors
|
||||
}
|
||||
|
||||
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
nsCString spec;
|
||||
uint32_t line = 0;
|
||||
uint32_t column = 0;
|
||||
ExtractErrorValues(aCx, aValue, spec, &line, &column, mRejectValue);
|
||||
|
||||
// only use the extracted location if we found one
|
||||
if (!spec.IsEmpty()) {
|
||||
mSourceSpec = spec;
|
||||
mLine = line;
|
||||
mColumn = column;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &WaitUntilHandler::ReportOnMainThread);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
NS_DispatchToMainThread(runnable.forget())));
|
||||
}
|
||||
|
||||
void
|
||||
ReportOnMainThread()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
|
||||
// TODO: Make the error message a localized string. (bug 1222720)
|
||||
nsString message;
|
||||
message.AppendLiteral("Service worker event waitUntil() was passed a "
|
||||
"promise that rejected with '");
|
||||
message.Append(mRejectValue);
|
||||
message.AppendLiteral("'.");
|
||||
|
||||
// Note, there is a corner case where this won't report to the window
|
||||
// that triggered the error. Consider a navigation fetch event that
|
||||
// rejects waitUntil() without holding respondWith() open. In this case
|
||||
// there is no controlling document yet, the window did call .register()
|
||||
// because there is no documeny yet, and the navigation is no longer
|
||||
// being intercepted.
|
||||
|
||||
swm->ReportToAllClients(mScope, message, NS_ConvertUTF8toUTF16(mSourceSpec),
|
||||
EmptyString(), mLine, mColumn,
|
||||
nsIScriptError::errorFlag);
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(WaitUntilHandler)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FetchEvent, ExtendableEvent)
|
||||
NS_IMPL_RELEASE_INHERITED(FetchEvent, ExtendableEvent)
|
||||
|
||||
@ -753,7 +843,7 @@ ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
|
||||
}
|
||||
|
||||
void
|
||||
ExtendableEvent::WaitUntil(Promise& aPromise, ErrorResult& aRv)
|
||||
ExtendableEvent::WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
@ -762,6 +852,12 @@ ExtendableEvent::WaitUntil(Promise& aPromise, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
|
||||
// Append our handler to each waitUntil promise separately so we
|
||||
// can record the location in script where waitUntil was called.
|
||||
RefPtr<WaitUntilHandler> handler =
|
||||
new WaitUntilHandler(GetCurrentThreadWorkerPrivate(), aCx);
|
||||
aPromise.AppendNativeHandler(handler);
|
||||
|
||||
mPromises.AppendElement(&aPromise);
|
||||
}
|
||||
|
||||
|
@ -51,9 +51,9 @@ public:
|
||||
|
||||
class ExtendableEvent : public Event
|
||||
{
|
||||
protected:
|
||||
nsTArray<RefPtr<Promise>> mPromises;
|
||||
|
||||
protected:
|
||||
explicit ExtendableEvent(mozilla::dom::EventTarget* aOwner);
|
||||
~ExtendableEvent() {}
|
||||
|
||||
@ -90,7 +90,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
WaitUntil(Promise& aPromise, ErrorResult& aRv);
|
||||
WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetPromise();
|
||||
|
@ -406,21 +406,10 @@ public:
|
||||
NS_RUNTIMEABORT("Failed to dispatch life cycle event handler.");
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, workerPrivate->GlobalScope()->GetWrapper());
|
||||
JS::ExposeValueToActiveJS(aValue);
|
||||
|
||||
js::ErrorReport report(aCx);
|
||||
if (NS_WARN_IF(!report.init(aCx, aValue))) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
xpcReport->Init(report.report(), report.message(),
|
||||
/* aIsChrome = */ false, workerPrivate->WindowID());
|
||||
|
||||
RefPtr<AsyncErrorReporter> aer = new AsyncErrorReporter(xpcReport);
|
||||
NS_DispatchToMainThread(aer);
|
||||
// Note, all WaitUntil() rejections are reported to client consoles
|
||||
// by the WaitUntilHandler in ServiceWorkerEvents. This ensures that
|
||||
// errors in non-lifecycle events like FetchEvent and PushEvent are
|
||||
// reported properly.
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user