/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * The spec mandates slightly different behaviors for computing the scope * prefix string in case a Service-Worker-Allowed header is specified versus * when it's not available. * * With the header: * "Set maxScopeString to "/" concatenated with the strings in maxScope's * path (including empty strings), separated from each other by "/"." * Without the header: * "Set maxScopeString to "/" concatenated with the strings, except the last * string that denotes the script's file name, in registration's registering * script url's path (including empty strings), separated from each other by * "/"." * * In simpler terms, if the header is not present, we should only use the * "directory" part of the pathname, and otherwise the entire pathname should be * used. ScopeStringPrefixMode allows the caller to specify the desired * behavior.
*/ enum ScopeStringPrefixMode { eUseDirectory, eUsePath };
class ServiceWorkerUpdateJob::ContinueUpdateRunnable final
: public LifeCycleEventCallback {
nsMainThreadPtrHandle<ServiceWorkerUpdateJob> mJob; bool mSuccess;
class ServiceWorkerUpdateJob::ContinueInstallRunnable final
: public LifeCycleEventCallback {
nsMainThreadPtrHandle<ServiceWorkerUpdateJob> mJob; bool mSuccess;
// Cleanup after a failed installation. This essentially implements // step 13 of the Install algorithm. // // https://w3c.github.io/ServiceWorker/#installation-algorithm // // The spec currently only runs this after an install event fails, // but we must handle many more internal errors. So we check for // cleanup on every non-successful exit. if (mRegistration) { // Some kinds of failures indicate there is something broken in the // currently installed registration. In these cases we want to fully // unregister. if (mOnFailure == OnFailure::Uninstall) {
mRegistration->ClearAsCorrupt();
}
// Otherwise just clear the workers we may have created as part of the // update process. else {
mRegistration->ClearEvaluating();
mRegistration->ClearInstalling();
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); if (swm) {
swm->MaybeRemoveRegistration(mRegistration);
// Also clear the registration on disk if we are forcing uninstall // due to a particularly bad failure. if (mOnFailure == OnFailure::Uninstall) {
swm->MaybeSendUnregister(mRegistration->Principal(),
mRegistration->Scope());
}
}
}
mRegistration = nullptr;
Finish(aRv);
}
void ServiceWorkerUpdateJob::FailUpdateJob(nsresult aRv) {
ErrorResult rv(aRv);
FailUpdateJob(rv); // This signature is intentionally about not using the result, so we do need // to suppress the exception.
rv.SuppressException();
}
// Invoke Update algorithm: // https://w3c.github.io/ServiceWorker/#update-algorithm // // "Let registration be the result of running the Get Registration algorithm // passing job’s scope url as the argument."
RefPtr<ServiceWorkerRegistrationInfo> registration =
swm->GetRegistration(mPrincipal, mScope);
if (!registration) {
ErrorResult rv;
rv.ThrowTypeError<MSG_SW_UPDATE_BAD_REGISTRATION>(mScope, "uninstalled");
FailUpdateJob(rv); return;
}
// "Let newestWorker be the result of running Get Newest Worker algorithm // passing registration as the argument."
RefPtr<ServiceWorkerInfo> newest = registration->Newest();
// "If job’s job type is update, and newestWorker is not null and its script // url does not equal job’s script url, then: // 1. Invoke Reject Job Promise with job and TypeError. // 2. Invoke Finish Job with job and abort these steps." if (newest && !newest->ScriptSpec().Equals(mScriptSpec)) {
ErrorResult rv;
rv.ThrowTypeError<MSG_SW_UPDATE_BAD_REGISTRATION>(mScope, "changed");
FailUpdateJob(rv); return;
}
// If the script has not changed, we need to perform a byte-for-byte // comparison. if (workerInfo && workerInfo->ScriptSpec().Equals(mScriptSpec)) {
cacheName = workerInfo->CacheName();
}
RefPtr<CompareCallback> callback = new CompareCallback(this);
// 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.
// 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;
}
// Begin step 7 of the Update algorithm to evaluate the new script.
nsLoadFlags flags = aLoadFlags; if (GetUpdateViaCache() == ServiceWorkerUpdateViaCache::None) {
flags |= nsIRequest::VALIDATE_ALWAYS;
}
// If the registration is corrupt enough to force an uninstall if the // upgrade fails, then we want to make sure the upgrade takes effect // if it succeeds. Therefore force the skip-waiting flag on to replace // the broken worker after install. if (aOnFailure == OnFailure::Uninstall) {
sw->SetSkipWaitingFlag();
}
mRegistration->SetEvaluating(sw);
nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle( new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>( "ServiceWorkerUpdateJob", this));
RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle);
ServiceWorkerPrivate* workerPrivate = sw->WorkerPrivate();
MOZ_ASSERT(workerPrivate); // Note that there are some synchronous failure cases that may immediately // invoke the callback, meaning that FailUpdateJob may have already been // called before this method returns.
rv = workerPrivate->CheckScriptEvaluation(mLifetimeExtension, callback);
// We call FailUpdateJob because it is idempotent and as defense-in-depth // against early errors returns potentially being introduced above that return // with ensuring that the passed-in callback will be invoked (such as those // that are frequently added for shutdown phases). if (NS_WARN_IF(NS_FAILED(rv))) {
FailUpdateJob(NS_ERROR_DOM_ABORT_ERR); return;
}
}
// If we haven't been canceled we should have a registration. There appears // to be a path where it gets cleared before we call into here. Assert // to try to catch this condition, but don't crash in release.
MOZ_DIAGNOSTIC_ASSERT(mRegistration); if (!mRegistration) { return FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
}
// Continue executing the Install algorithm at step 12.
// "If installFailed is true" if (NS_WARN_IF(!aInstallEventSuccess)) { // The installing worker is cleaned up by FailUpdateJob().
FailUpdateJob(NS_ERROR_DOM_ABORT_ERR); return;
}
// Abort the update Job if the installWorker is null (e.g. when an extension // is shutting down and all its workers have been terminated). if (!mRegistration->GetInstalling()) { return FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
}
mRegistration->TransitionInstallingToWaiting();
Finish(NS_OK);
// Step 20 calls for explicitly waiting for queued event tasks to fire. // Instead, we simply queue a runnable to execute Activate. This ensures the // events are flushed from the queue before proceeding.
// Step 22 of the Install algorithm. Activate is executed after the // completion of this job. The controlling client and skipWaiting checks are // performed in TryToActivate().
mRegistration->TryToActivateAsync(mLifetimeExtension);
}
} // namespace mozilla::dom
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.