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 ServiceWorkerRegistrationInfo::Activate() { if (!mWaitingWorker) { return; } RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); if (!swm) { // browser shutdown began during async activation step return; } TransitionWaitingToActive(); // FIXME(nsm): Unlink appcache if there is one. swm->CheckPendingReadyPromises(); // "Queue a task to fire a simple event named controllerchange..." nsCOMPtr<nsIRunnable> controllerChangeRunnable = NewRunnableMethod<RefPtr<ServiceWorkerRegistrationInfo>>( swm, &ServiceWorkerManager::FireControllerChange, this); NS_DispatchToMainThread(controllerChangeRunnable); nsCOMPtr<nsIRunnable> failRunnable = NewRunnableMethod<bool>(this, &ServiceWorkerRegistrationInfo::FinishActivate, false /* success */); nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle( new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(this)); RefPtr<LifeCycleEventCallback> callback = new ContinueActivateRunnable(handle); ServiceWorkerPrivate* workerPrivate = mActiveWorker->WorkerPrivate(); MOZ_ASSERT(workerPrivate); nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("activate"), callback, failRunnable); if (NS_WARN_IF(NS_FAILED(rv))) { MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(failRunnable)); return; } }
void ServiceWorkerUpdateJob::ComparisonResult(nsresult aStatus, bool aInCacheAndEqual, const nsAString& aNewCacheName, const nsACString& aMaxScope, nsLoadFlags aLoadFlags) { AssertIsOnMainThread(); RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); if (NS_WARN_IF(Canceled() || !swm)) { FailUpdateJob(NS_ERROR_DOM_ABORT_ERR); return; } // Handle failure of the download or comparison. This is part of Update // step 5 as "If the algorithm asynchronously completes with null, then:". if (NS_WARN_IF(NS_FAILED(aStatus))) { FailUpdateJob(aStatus); return; } // The spec validates the response before performing the byte-for-byte check. // Here we perform the comparison in another module and then validate the // script URL and scope. Make sure to do this validation before accepting // an byte-for-byte match since the service-worker-allowed header might have // changed since the last time it was installed. // This is step 2 the "validate response" section of Update algorithm step 5. // Step 1 is performed in the serviceWorkerScriptCache code. nsCOMPtr<nsIURI> scriptURI; nsresult rv = NS_NewURI(getter_AddRefs(scriptURI), mScriptSpec); if (NS_WARN_IF(NS_FAILED(rv))) { FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR); return; } nsCOMPtr<nsIURI> maxScopeURI; if (!aMaxScope.IsEmpty()) { rv = NS_NewURI(getter_AddRefs(maxScopeURI), aMaxScope, nullptr, scriptURI); if (NS_WARN_IF(NS_FAILED(rv))) { FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR); return; } } mLoadFlags = aLoadFlags; nsAutoCString defaultAllowedPrefix; rv = GetRequiredScopeStringPrefix(scriptURI, defaultAllowedPrefix, eUseDirectory); if (NS_WARN_IF(NS_FAILED(rv))) { FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR); return; } nsAutoCString maxPrefix(defaultAllowedPrefix); if (maxScopeURI) { rv = GetRequiredScopeStringPrefix(maxScopeURI, maxPrefix, eUsePath); if (NS_WARN_IF(NS_FAILED(rv))) { FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR); return; } } if (!StringBeginsWith(mRegistration->mScope, maxPrefix)) { nsAutoString message; NS_ConvertUTF8toUTF16 reportScope(mRegistration->mScope); NS_ConvertUTF8toUTF16 reportMaxPrefix(maxPrefix); const char16_t* params[] = { reportScope.get(), reportMaxPrefix.get() }; rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES, "ServiceWorkerScopePathMismatch", params, message); NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to format localized string"); swm->ReportToAllClients(mScope, message, EmptyString(), EmptyString(), 0, 0, nsIScriptError::errorFlag); FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR); return; } // The response has been validated, so now we can consider if its a // byte-for-byte match. This is step 6 of the Update algorithm. if (aInCacheAndEqual) { Finish(NS_OK); return; } Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1); // Begin step 7 of the Update algorithm to evaluate the new script. RefPtr<ServiceWorkerInfo> sw = new ServiceWorkerInfo(mRegistration->mPrincipal, mRegistration->mScope, mScriptSpec, aNewCacheName, mLoadFlags); mRegistration->SetEvaluating(sw); nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle( new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>( "ServiceWorkerUpdateJob", this)); RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle); ServiceWorkerPrivate* workerPrivate = sw->WorkerPrivate(); MOZ_ASSERT(workerPrivate); rv = workerPrivate->CheckScriptEvaluation(callback); if (NS_WARN_IF(NS_FAILED(rv))) { FailUpdateJob(NS_ERROR_DOM_ABORT_ERR); return; } }