void ServiceWorkerUpdateJob::Install(ServiceWorkerManager* aSWM) { AssertIsOnMainThread(); MOZ_DIAGNOSTIC_ASSERT(!Canceled()); MOZ_DIAGNOSTIC_ASSERT(aSWM); MOZ_ASSERT(!mRegistration->GetInstalling()); // Begin step 2 of the Install algorithm. // // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm mRegistration->TransitionEvaluatingToInstalling(); // Step 6 of the Install algorithm resolving the job promise. InvokeResultCallbacks(NS_OK); // The job promise cannot be rejected after this point, but the job can // still fail; e.g. if the install event handler throws, etc. // fire the updatefound event nsCOMPtr<nsIRunnable> upr = NewRunnableMethod<RefPtr<ServiceWorkerRegistrationInfo>>( "dom::workers::ServiceWorkerManager::" "FireUpdateFoundOnServiceWorkerRegistrations", aSWM, &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations, mRegistration); NS_DispatchToMainThread(upr); // Call ContinueAfterInstallEvent(false) on main thread if the SW // script fails to load. nsCOMPtr<nsIRunnable> failRunnable = NewRunnableMethod<bool>( "dom::workers::ServiceWorkerUpdateJob::ContinueAfterInstallEvent", this, &ServiceWorkerUpdateJob::ContinueAfterInstallEvent, false); nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle( new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>( "ServiceWorkerUpdateJob", this)); RefPtr<LifeCycleEventCallback> callback = new ContinueInstallRunnable(handle); // Send the install event to the worker thread ServiceWorkerPrivate* workerPrivate = mRegistration->GetInstalling()->WorkerPrivate(); nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"), callback, failRunnable); if (NS_WARN_IF(NS_FAILED(rv))) { ContinueAfterInstallEvent(false /* aSuccess */); } }
void ServiceWorkerUnregisterJob::AsyncExecute() { AssertIsOnMainThread(); if (Canceled()) { Finish(NS_ERROR_DOM_ABORT_ERR); return; } // Step 1 of the Unregister algorithm requires checking that the // client origin matches the scope's origin. We perform this in // registration->update() method directly since we don't have that // client information available here. RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); // "Let registration be the result of running [[Get Registration]] // algorithm passing scope as the argument." RefPtr<ServiceWorkerRegistrationInfo> registration = swm->GetRegistration(mPrincipal, mScope); if (!registration) { // "If registration is null, then, resolve promise with false." Finish(NS_OK); return; } // Note, we send the message to remove the registration from disk now even // though we may only set the mPendingUninstall flag below. This is // necessary to ensure the registration is removed if the controlled // clients are closed by shutting down the browser. If the registration // is resurrected by clearing mPendingUninstall then it should be saved // to disk again. if (mSendToParent && !registration->mPendingUninstall) { swm->MaybeSendUnregister(mPrincipal, mScope); } // "Set registration's uninstalling flag." registration->mPendingUninstall = true; // "Resolve promise with true" mResult = true; InvokeResultCallbacks(NS_OK); // "If no service worker client is using registration..." if (!registration->IsControllingDocuments()) { // "Invoke [[Clear Registration]]..." swm->RemoveRegistration(registration); } Finish(NS_OK); }
void ServiceWorkerJob::Finish(ErrorResult& aRv) { AssertIsOnMainThread(); MOZ_ASSERT(mState == State::Started); // Ensure that we only surface SecurityErr, TypeErr or InvalidStateErr to script. if (aRv.Failed() && !aRv.ErrorCodeIs(NS_ERROR_DOM_SECURITY_ERR) && !aRv.ErrorCodeIs(NS_ERROR_DOM_TYPE_ERR) && !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR)) { // Remove the old error code so we can replace it with a TypeError. aRv.SuppressException(); NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec); NS_ConvertUTF8toUTF16 scope(mScope); // Throw the type error with a generic error message. aRv.ThrowTypeError<MSG_SW_INSTALL_ERROR>(scriptSpec, scope); } // The final callback may drop the last ref to this object. RefPtr<ServiceWorkerJob> kungFuDeathGrip = this; if (!mResultCallbacksInvoked) { InvokeResultCallbacks(aRv); } mState = State::Finished; mFinalCallback->JobFinished(this, aRv); mFinalCallback = nullptr; // The callback might not consume the error. aRv.SuppressException(); // Async release this object to ensure that our caller methods complete // as well. NS_ReleaseOnMainThread(kungFuDeathGrip.forget(), true /* always proxy */); }
void ServiceWorkerJob::InvokeResultCallbacks(nsresult aRv) { ErrorResult converted(aRv); InvokeResultCallbacks(converted); }