mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Backed out changeset b2d3c6629a37 (bug 1263304
)
This commit is contained in:
parent
933a225285
commit
e84cb96866
@ -767,9 +767,9 @@ FetchEvent::RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv)
|
|||||||
spec, line, column);
|
spec, line, column);
|
||||||
aArg.AppendNativeHandler(handler);
|
aArg.AppendNativeHandler(handler);
|
||||||
|
|
||||||
if (!WaitOnPromise(aArg)) {
|
// Append directly to the lifecycle promises array. Don't call WaitUntil()
|
||||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
// because that will lead to double-reporting any errors.
|
||||||
}
|
mPromises.AppendElement(&aArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -910,29 +910,12 @@ ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
ExtendableEvent::WaitOnPromise(Promise& aPromise)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mExtensionsHandler);
|
|
||||||
return mExtensionsHandler->WaitOnPromise(aPromise);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ExtendableEvent::SetKeepAliveHandler(ExtensionsHandler* aExtensionsHandler)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!mExtensionsHandler);
|
|
||||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
|
||||||
MOZ_ASSERT(worker);
|
|
||||||
worker->AssertIsOnWorkerThread();
|
|
||||||
mExtensionsHandler = aExtensionsHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ExtendableEvent::WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv)
|
ExtendableEvent::WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
|
||||||
if (!WaitOnPromise(aPromise)) {
|
if (EventPhase() == nsIDOMEvent::NONE) {
|
||||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -942,6 +925,34 @@ ExtendableEvent::WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv)
|
|||||||
RefPtr<WaitUntilHandler> handler =
|
RefPtr<WaitUntilHandler> handler =
|
||||||
new WaitUntilHandler(GetCurrentThreadWorkerPrivate(), aCx);
|
new WaitUntilHandler(GetCurrentThreadWorkerPrivate(), aCx);
|
||||||
aPromise.AppendNativeHandler(handler);
|
aPromise.AppendNativeHandler(handler);
|
||||||
|
|
||||||
|
mPromises.AppendElement(&aPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<Promise>
|
||||||
|
ExtendableEvent::GetPromise()
|
||||||
|
{
|
||||||
|
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||||
|
MOZ_ASSERT(worker);
|
||||||
|
worker->AssertIsOnWorkerThread();
|
||||||
|
|
||||||
|
nsIGlobalObject* globalObj = worker->GlobalScope();
|
||||||
|
|
||||||
|
AutoJSAPI jsapi;
|
||||||
|
if (!jsapi.Init(globalObj)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
JSContext* cx = jsapi.cx();
|
||||||
|
|
||||||
|
GlobalObject global(cx, globalObj->GetGlobalJSObject());
|
||||||
|
|
||||||
|
ErrorResult result;
|
||||||
|
RefPtr<Promise> p = Promise::All(global, Move(mPromises), result);
|
||||||
|
if (NS_WARN_IF(result.MaybeSetPendingException(cx))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ADDREF_INHERITED(ExtendableEvent, Event)
|
NS_IMPL_ADDREF_INHERITED(ExtendableEvent, Event)
|
||||||
@ -950,6 +961,8 @@ NS_IMPL_RELEASE_INHERITED(ExtendableEvent, Event)
|
|||||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ExtendableEvent)
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ExtendableEvent)
|
||||||
NS_INTERFACE_MAP_END_INHERITING(Event)
|
NS_INTERFACE_MAP_END_INHERITING(Event)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(ExtendableEvent, Event, mPromises)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
nsresult
|
nsresult
|
||||||
ExtractBytesFromUSVString(const nsAString& aStr, nsTArray<uint8_t>& aBytes)
|
ExtractBytesFromUSVString(const nsAString& aStr, nsTArray<uint8_t>& aBytes)
|
||||||
|
@ -51,36 +51,17 @@ public:
|
|||||||
|
|
||||||
class ExtendableEvent : public Event
|
class ExtendableEvent : public Event
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
class ExtensionsHandler {
|
|
||||||
public:
|
|
||||||
virtual bool
|
|
||||||
WaitOnPromise(Promise& aPromise) = 0;
|
|
||||||
|
|
||||||
NS_IMETHOD_(MozExternalRefCountType)
|
|
||||||
AddRef() = 0;
|
|
||||||
|
|
||||||
NS_IMETHOD_(MozExternalRefCountType)
|
|
||||||
Release() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<ExtensionsHandler> mExtensionsHandler;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool
|
nsTArray<RefPtr<Promise>> mPromises;
|
||||||
WaitOnPromise(Promise& aPromise);
|
|
||||||
|
|
||||||
explicit ExtendableEvent(mozilla::dom::EventTarget* aOwner);
|
explicit ExtendableEvent(mozilla::dom::EventTarget* aOwner);
|
||||||
~ExtendableEvent() {}
|
~ExtendableEvent() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ExtendableEvent, Event)
|
||||||
NS_FORWARD_TO_EVENT
|
NS_FORWARD_TO_EVENT
|
||||||
|
|
||||||
void
|
|
||||||
SetKeepAliveHandler(ExtensionsHandler* aExtensionsHandler);
|
|
||||||
|
|
||||||
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
|
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
|
||||||
{
|
{
|
||||||
return mozilla::dom::ExtendableEventBinding::Wrap(aCx, this, aGivenProto);
|
return mozilla::dom::ExtendableEventBinding::Wrap(aCx, this, aGivenProto);
|
||||||
@ -112,6 +93,9 @@ public:
|
|||||||
void
|
void
|
||||||
WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv);
|
WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv);
|
||||||
|
|
||||||
|
already_AddRefed<Promise>
|
||||||
|
GetPromise();
|
||||||
|
|
||||||
virtual ExtendableEvent* AsExtendableEvent() override
|
virtual ExtendableEvent* AsExtendableEvent() override
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
|
@ -181,186 +181,154 @@ ServiceWorkerPrivate::CheckScriptEvaluation(LifeCycleEventCallback* aCallback)
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum ExtendableEventResult {
|
// Holds the worker alive until the waitUntil promise is resolved or
|
||||||
Rejected = 0,
|
// rejected.
|
||||||
Resolved
|
class KeepAliveHandler final
|
||||||
};
|
|
||||||
|
|
||||||
class ExtendableEventCallback {
|
|
||||||
public:
|
|
||||||
virtual void
|
|
||||||
FinishedWithResult(ExtendableEventResult aResult) = 0;
|
|
||||||
|
|
||||||
NS_IMETHOD_(MozExternalRefCountType)
|
|
||||||
AddRef() = 0;
|
|
||||||
|
|
||||||
NS_IMETHOD_(MozExternalRefCountType)
|
|
||||||
Release() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class KeepAliveHandler final : public WorkerHolder
|
|
||||||
, public ExtendableEvent::ExtensionsHandler
|
|
||||||
, public PromiseNativeHandler
|
|
||||||
{
|
{
|
||||||
// This class manages lifetime extensions added by calling WaitUntil()
|
// Use an internal class to listen for the promise resolve/reject
|
||||||
// or RespondWith(). We allow new extensions as long as we still hold
|
// callbacks. This class also registers a feature so that it can
|
||||||
// |mKeepAliveToken|. Once the last promise was settled, we queue a microtask
|
// preemptively cleanup if the service worker is timed out and
|
||||||
// which releases the token and prevents further extensions. By doing this,
|
// terminated.
|
||||||
// we give other pending microtasks a chance to continue adding extensions.
|
class InternalHandler final : public PromiseNativeHandler
|
||||||
|
, public WorkerHolder
|
||||||
nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
|
|
||||||
WorkerPrivate* MOZ_NON_OWNING_REF mWorkerPrivate;
|
|
||||||
bool mWorkerHolderAdded;
|
|
||||||
|
|
||||||
// We start holding a self reference when the first extension promise is
|
|
||||||
// added. As far as I can tell, the only case where this is useful is when
|
|
||||||
// we're waiting indefinitely on a promise that's no longer reachable
|
|
||||||
// and will never be settled.
|
|
||||||
// The cycle is broken when the last promise was settled or when the
|
|
||||||
// worker is shutting down.
|
|
||||||
RefPtr<KeepAliveHandler> mSelfRef;
|
|
||||||
|
|
||||||
// Called when the last promise was settled.
|
|
||||||
RefPtr<ExtendableEventCallback> mCallback;
|
|
||||||
|
|
||||||
uint32_t mPendingPromisesCount;
|
|
||||||
|
|
||||||
// We don't actually care what values the promises resolve to, only whether
|
|
||||||
// any of them were rejected.
|
|
||||||
bool mRejected;
|
|
||||||
|
|
||||||
public:
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
|
|
||||||
explicit KeepAliveHandler(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
|
|
||||||
ExtendableEventCallback* aCallback)
|
|
||||||
: mKeepAliveToken(aKeepAliveToken)
|
|
||||||
, mWorkerPrivate(GetCurrentThreadWorkerPrivate())
|
|
||||||
, mWorkerHolderAdded(false)
|
|
||||||
, mCallback(aCallback)
|
|
||||||
, mPendingPromisesCount(0)
|
|
||||||
, mRejected(false)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mKeepAliveToken);
|
nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
|
||||||
MOZ_ASSERT(mWorkerPrivate);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
// Worker thread only
|
||||||
UseWorkerHolder()
|
WorkerPrivate* mWorkerPrivate;
|
||||||
{
|
RefPtr<Promise> mPromise;
|
||||||
MOZ_ASSERT(mWorkerPrivate);
|
bool mWorkerHolderAdded;
|
||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
||||||
MOZ_ASSERT(!mWorkerHolderAdded);
|
|
||||||
mWorkerHolderAdded = HoldWorker(mWorkerPrivate, Terminating);
|
|
||||||
return mWorkerHolderAdded;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
~InternalHandler()
|
||||||
WaitOnPromise(Promise& aPromise) override
|
{
|
||||||
{
|
MaybeCleanup();
|
||||||
if (!mKeepAliveToken) {
|
|
||||||
MOZ_ASSERT(!mSelfRef, "We shouldn't be holding a self reference!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!mSelfRef) {
|
|
||||||
MOZ_ASSERT(!mPendingPromisesCount);
|
|
||||||
mSelfRef = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++mPendingPromisesCount;
|
bool
|
||||||
aPromise.AppendNativeHandler(this);
|
UseWorkerHolder()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mWorkerPrivate);
|
||||||
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
MOZ_ASSERT(!mWorkerHolderAdded);
|
||||||
|
mWorkerHolderAdded = HoldWorker(mWorkerPrivate, Terminating);
|
||||||
|
return mWorkerHolderAdded;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
void
|
||||||
}
|
MaybeCleanup()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mWorkerPrivate);
|
||||||
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
if (!mPromise) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mWorkerHolderAdded) {
|
||||||
|
ReleaseWorker();
|
||||||
|
}
|
||||||
|
mPromise = nullptr;
|
||||||
|
mKeepAliveToken = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
{
|
{
|
||||||
RemovePromise(Resolved);
|
MOZ_ASSERT(mWorkerPrivate);
|
||||||
}
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
MaybeCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
{
|
{
|
||||||
RemovePromise(Rejected);
|
MOZ_ASSERT(mWorkerPrivate);
|
||||||
}
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
MaybeCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Notify(Status aStatus) override
|
Notify(Status aStatus) override
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mWorkerPrivate);
|
MOZ_ASSERT(mWorkerPrivate);
|
||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
if (aStatus < Terminating) {
|
if (aStatus < Terminating) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
MaybeCleanup();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeCleanup();
|
InternalHandler(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
|
||||||
return true;
|
WorkerPrivate* aWorkerPrivate,
|
||||||
}
|
Promise* aPromise)
|
||||||
|
: mKeepAliveToken(aKeepAliveToken)
|
||||||
void
|
, mWorkerPrivate(aWorkerPrivate)
|
||||||
MaybeDone()
|
, mPromise(aPromise)
|
||||||
{
|
, mWorkerHolderAdded(false)
|
||||||
MOZ_ASSERT(mWorkerPrivate);
|
{
|
||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
MOZ_ASSERT(mKeepAliveToken);
|
||||||
|
MOZ_ASSERT(mWorkerPrivate);
|
||||||
if (mPendingPromisesCount) {
|
MOZ_ASSERT(mPromise);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mCallback) {
|
|
||||||
mCallback->FinishedWithResult(mRejected ? Rejected : Resolved);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeCleanup();
|
public:
|
||||||
}
|
static already_AddRefed<InternalHandler>
|
||||||
|
Create(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
|
||||||
|
WorkerPrivate* aWorkerPrivate,
|
||||||
|
Promise* aPromise)
|
||||||
|
{
|
||||||
|
RefPtr<InternalHandler> ref = new InternalHandler(aKeepAliveToken,
|
||||||
|
aWorkerPrivate,
|
||||||
|
aPromise);
|
||||||
|
|
||||||
private:
|
if (NS_WARN_IF(!ref->UseWorkerHolder())) {
|
||||||
~KeepAliveHandler()
|
return nullptr;
|
||||||
{
|
}
|
||||||
MaybeCleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
return ref.forget();
|
||||||
MaybeCleanup()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mWorkerPrivate);
|
|
||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
||||||
if (!mKeepAliveToken) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mWorkerHolderAdded) {
|
|
||||||
ReleaseWorker();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mKeepAliveToken = nullptr;
|
NS_DECL_ISUPPORTS
|
||||||
mSelfRef = nullptr;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
void
|
// This is really just a wrapper class to keep the InternalHandler
|
||||||
RemovePromise(ExtendableEventResult aResult)
|
// private. We don't want any code to accidentally call
|
||||||
|
// Promise::AppendNativeHandler() without also referencing the promise.
|
||||||
|
// Therefore we force all code through the static CreateAndAttachToPromise()
|
||||||
|
// and use the private InternalHandler object.
|
||||||
|
KeepAliveHandler() = delete;
|
||||||
|
~KeepAliveHandler() = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Create a private handler object and attach it to the given Promise.
|
||||||
|
// This will also create a strong ref to the Promise in a ref cycle. The
|
||||||
|
// ref cycle is broken when the Promise is fulfilled or the worker thread
|
||||||
|
// is Terminated.
|
||||||
|
static void
|
||||||
|
CreateAndAttachToPromise(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
|
||||||
|
Promise* aPromise)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mWorkerPrivate);
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
MOZ_ASSERT(workerPrivate);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mPendingPromisesCount > 0);
|
workerPrivate->AssertIsOnWorkerThread();
|
||||||
MOZ_ASSERT(mSelfRef);
|
MOZ_ASSERT(aKeepAliveToken);
|
||||||
MOZ_ASSERT(mKeepAliveToken);
|
MOZ_ASSERT(aPromise);
|
||||||
|
|
||||||
mRejected |= (aResult == Rejected);
|
// This creates a strong ref to the promise.
|
||||||
|
RefPtr<InternalHandler> handler = InternalHandler::Create(aKeepAliveToken,
|
||||||
--mPendingPromisesCount;
|
workerPrivate,
|
||||||
if (mPendingPromisesCount) {
|
aPromise);
|
||||||
|
if (NS_WARN_IF(!handler)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CycleCollectedJSContext* cx = CycleCollectedJSContext::Get();
|
// This then creates a strong ref cycle between the promise and the
|
||||||
MOZ_ASSERT(cx);
|
// handler. The cycle is broken when the Promise is fulfilled or
|
||||||
|
// the worker thread is Terminated.
|
||||||
RefPtr<nsIRunnable> r = NewRunnableMethod(this, &KeepAliveHandler::MaybeDone);
|
aPromise->AppendNativeHandler(handler);
|
||||||
cx->DispatchToMicroTask(r.forget());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS0(KeepAliveHandler)
|
NS_IMPL_ISUPPORTS0(KeepAliveHandler::InternalHandler)
|
||||||
|
|
||||||
class RegistrationUpdateRunnable : public Runnable
|
class RegistrationUpdateRunnable : public Runnable
|
||||||
{
|
{
|
||||||
@ -409,23 +377,13 @@ public:
|
|||||||
DispatchExtendableEventOnWorkerScope(JSContext* aCx,
|
DispatchExtendableEventOnWorkerScope(JSContext* aCx,
|
||||||
WorkerGlobalScope* aWorkerScope,
|
WorkerGlobalScope* aWorkerScope,
|
||||||
ExtendableEvent* aEvent,
|
ExtendableEvent* aEvent,
|
||||||
ExtendableEventCallback* aCallback)
|
PromiseNativeHandler* aPromiseHandler)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aWorkerScope);
|
MOZ_ASSERT(aWorkerScope);
|
||||||
MOZ_ASSERT(aEvent);
|
MOZ_ASSERT(aEvent);
|
||||||
nsCOMPtr<nsIGlobalObject> sgo = aWorkerScope;
|
nsCOMPtr<nsIGlobalObject> sgo = aWorkerScope;
|
||||||
WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
|
WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
|
||||||
|
|
||||||
RefPtr<KeepAliveHandler> keepAliveHandler =
|
|
||||||
new KeepAliveHandler(mKeepAliveToken, aCallback);
|
|
||||||
if (NS_WARN_IF(!keepAliveHandler->UseWorkerHolder())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This must always be set *before* dispatching the event, otherwise
|
|
||||||
// waitUntil calls will fail.
|
|
||||||
aEvent->SetKeepAliveHandler(keepAliveHandler);
|
|
||||||
|
|
||||||
ErrorResult result;
|
ErrorResult result;
|
||||||
result = aWorkerScope->DispatchDOMEvent(nullptr, aEvent, nullptr, nullptr);
|
result = aWorkerScope->DispatchDOMEvent(nullptr, aEvent, nullptr, nullptr);
|
||||||
if (NS_WARN_IF(result.Failed()) || internalEvent->mFlags.mExceptionWasRaised) {
|
if (NS_WARN_IF(result.Failed()) || internalEvent->mFlags.mExceptionWasRaised) {
|
||||||
@ -433,9 +391,26 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [[ If e’s extend lifetime promises is empty, unset e’s extensions allowed
|
RefPtr<Promise> waitUntilPromise = aEvent->GetPromise();
|
||||||
// flag and abort these steps. ]]
|
if (!waitUntilPromise) {
|
||||||
keepAliveHandler->MaybeDone();
|
waitUntilPromise =
|
||||||
|
Promise::Resolve(sgo, aCx, JS::UndefinedHandleValue, result);
|
||||||
|
MOZ_RELEASE_ASSERT(!result.Failed());
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(waitUntilPromise);
|
||||||
|
|
||||||
|
// Make sure to append the caller's promise handler before attaching
|
||||||
|
// our keep alive handler. This can avoid terminating the worker
|
||||||
|
// before a success result is delivered to the caller in cases where
|
||||||
|
// the idle timeout has been set to zero. This low timeout value is
|
||||||
|
// sometimes set in tests.
|
||||||
|
if (aPromiseHandler) {
|
||||||
|
waitUntilPromise->AppendNativeHandler(aPromiseHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeepAliveHandler::CreateAndAttachToPromise(mKeepAliveToken,
|
||||||
|
waitUntilPromise);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -626,7 +601,7 @@ private:
|
|||||||
* termination during the execution of life cycle events. It is responsible
|
* termination during the execution of life cycle events. It is responsible
|
||||||
* with advancing the job queue for install/activate tasks.
|
* with advancing the job queue for install/activate tasks.
|
||||||
*/
|
*/
|
||||||
class LifeCycleEventWatcher final : public ExtendableEventCallback,
|
class LifeCycleEventWatcher final : public PromiseNativeHandler,
|
||||||
public WorkerHolder
|
public WorkerHolder
|
||||||
{
|
{
|
||||||
WorkerPrivate* mWorkerPrivate;
|
WorkerPrivate* mWorkerPrivate;
|
||||||
@ -648,7 +623,7 @@ class LifeCycleEventWatcher final : public ExtendableEventCallback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_REFCOUNTING(LifeCycleEventWatcher, override)
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
LifeCycleEventWatcher(WorkerPrivate* aWorkerPrivate,
|
LifeCycleEventWatcher(WorkerPrivate* aWorkerPrivate,
|
||||||
LifeCycleEventCallback* aCallback)
|
LifeCycleEventCallback* aCallback)
|
||||||
@ -715,11 +690,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FinishedWithResult(ExtendableEventResult aResult) override
|
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
|
MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
|
||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
ReportResult(aResult == Resolved);
|
|
||||||
|
ReportResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
|
||||||
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
|
||||||
|
ReportResult(false);
|
||||||
|
|
||||||
// Note, all WaitUntil() rejections are reported to client consoles
|
// Note, all WaitUntil() rejections are reported to client consoles
|
||||||
// by the WaitUntilHandler in ServiceWorkerEvents. This ensures that
|
// by the WaitUntilHandler in ServiceWorkerEvents. This ensures that
|
||||||
@ -728,6 +713,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS0(LifeCycleEventWatcher)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx,
|
LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx,
|
||||||
WorkerPrivate* aWorkerPrivate)
|
WorkerPrivate* aWorkerPrivate)
|
||||||
@ -791,7 +778,7 @@ ServiceWorkerPrivate::SendLifeCycleEvent(const nsAString& aEventType,
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class PushErrorReporter final : public ExtendableEventCallback
|
class PushErrorReporter final : public PromiseNativeHandler
|
||||||
{
|
{
|
||||||
WorkerPrivate* mWorkerPrivate;
|
WorkerPrivate* mWorkerPrivate;
|
||||||
nsString mMessageId;
|
nsString mMessageId;
|
||||||
@ -801,7 +788,7 @@ class PushErrorReporter final : public ExtendableEventCallback
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PushErrorReporter, override)
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
|
||||||
PushErrorReporter(WorkerPrivate* aWorkerPrivate,
|
PushErrorReporter(WorkerPrivate* aWorkerPrivate,
|
||||||
const nsAString& aMessageId)
|
const nsAString& aMessageId)
|
||||||
@ -811,12 +798,16 @@ public:
|
|||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
FinishedWithResult(ExtendableEventResult aResult) override
|
|
||||||
{
|
{
|
||||||
if (aResult == Rejected) {
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
Report(nsIPushErrorReporter::DELIVERY_UNHANDLED_REJECTION);
|
mWorkerPrivate = nullptr;
|
||||||
}
|
// Do nothing; we only use this to report errors to the Push service.
|
||||||
|
}
|
||||||
|
|
||||||
|
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
|
{
|
||||||
|
Report(nsIPushErrorReporter::DELIVERY_UNHANDLED_REJECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Report(uint16_t aReason = nsIPushErrorReporter::DELIVERY_INTERNAL_ERROR)
|
void Report(uint16_t aReason = nsIPushErrorReporter::DELIVERY_INTERNAL_ERROR)
|
||||||
@ -848,6 +839,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS0(PushErrorReporter)
|
||||||
|
|
||||||
class SendPushEventRunnable final : public ExtendableFunctionalEventWorkerRunnable
|
class SendPushEventRunnable final : public ExtendableFunctionalEventWorkerRunnable
|
||||||
{
|
{
|
||||||
nsString mMessageId;
|
nsString mMessageId;
|
||||||
@ -1050,7 +1043,7 @@ private:
|
|||||||
RefPtr<AllowWindowInteractionHandler> mHandler;
|
RefPtr<AllowWindowInteractionHandler> mHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AllowWindowInteractionHandler final : public ExtendableEventCallback
|
class AllowWindowInteractionHandler final : public PromiseNativeHandler
|
||||||
{
|
{
|
||||||
friend class ClearWindowAllowedRunnable;
|
friend class ClearWindowAllowedRunnable;
|
||||||
nsCOMPtr<nsITimer> mTimer;
|
nsCOMPtr<nsITimer> mTimer;
|
||||||
@ -1129,7 +1122,7 @@ class AllowWindowInteractionHandler final : public ExtendableEventCallback
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_REFCOUNTING(AllowWindowInteractionHandler, override)
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
explicit AllowWindowInteractionHandler(WorkerPrivate* aWorkerPrivate)
|
explicit AllowWindowInteractionHandler(WorkerPrivate* aWorkerPrivate)
|
||||||
{
|
{
|
||||||
@ -1137,13 +1130,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FinishedWithResult(ExtendableEventResult /* aResult */) override
|
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
{
|
{
|
||||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||||
|
ClearWindowAllowed(workerPrivate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
|
{
|
||||||
|
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||||
ClearWindowAllowed(workerPrivate);
|
ClearWindowAllowed(workerPrivate);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS0(AllowWindowInteractionHandler)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ClearWindowAllowedRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
ClearWindowAllowedRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||||
{
|
{
|
||||||
@ -1232,7 +1234,7 @@ public:
|
|||||||
new AllowWindowInteractionHandler(aWorkerPrivate);
|
new AllowWindowInteractionHandler(aWorkerPrivate);
|
||||||
if (!DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
|
if (!DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
|
||||||
event, allowWindowInteraction)) {
|
event, allowWindowInteraction)) {
|
||||||
allowWindowInteraction->FinishedWithResult(Rejected);
|
allowWindowInteraction->RejectedCallback(aCx, JS::UndefinedHandleValue);
|
||||||
}
|
}
|
||||||
aWorkerPrivate->GlobalScope()->ConsumeWindowInteraction();
|
aWorkerPrivate->GlobalScope()->ConsumeWindowInteraction();
|
||||||
|
|
||||||
@ -1565,10 +1567,9 @@ private:
|
|||||||
event->PostInit(mInterceptedChannel, mRegistration, mScriptSpec);
|
event->PostInit(mInterceptedChannel, mRegistration, mScriptSpec);
|
||||||
event->SetTrusted(true);
|
event->SetTrusted(true);
|
||||||
|
|
||||||
bool rv2 =
|
RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
|
||||||
DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
|
nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||||
event, nullptr);
|
if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
|
||||||
if (NS_WARN_IF(!rv2) || !event->WaitToRespond()) {
|
|
||||||
nsCOMPtr<nsIRunnable> runnable;
|
nsCOMPtr<nsIRunnable> runnable;
|
||||||
if (event->DefaultPrevented(aCx)) {
|
if (event->DefaultPrevented(aCx)) {
|
||||||
event->ReportCanceled();
|
event->ReportCanceled();
|
||||||
@ -1587,6 +1588,12 @@ private:
|
|||||||
MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
|
MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<Promise> waitUntilPromise = event->GetPromise();
|
||||||
|
if (waitUntilPromise) {
|
||||||
|
KeepAliveHandler::CreateAndAttachToPromise(mKeepAliveToken,
|
||||||
|
waitUntilPromise);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user