Back out 13 changesets (bug 1226443, bug 1227015) for a variety of serviceworker web-platform-test failures
authorPhil Ringnalda <philringnalda@gmail.com>
Thu, 10 Dec 2015 18:49:48 -0800
changeset 276146 c873567c28985beea81409a53508ec804dc6ba05
parent 276145 a5fa1e187b98b5d9448f681c0ee4920fbda55288
child 276147 a58871d438cc47cc9e5b835b969ca27084cbbae4
push id69060
push userphilringnalda@gmail.com
push dateFri, 11 Dec 2015 02:50:01 +0000
treeherdermozilla-inbound@c873567c2898 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1226443, 1227015
milestone45.0a1
backs outd518261eb3b17f3e6b11fdb6d55ec1b7d4b11901
a7def186c1d3f25cf8c8fb150487849af0a2b6ae
e2f21ee1cd4cb118ec1c2794d48a2c1296c53ec2
8c4aff8bbfaff1a18e4b19bdf77edfd9a1600dff
4c85bf5e9bf52139410a9baa033e8f95380d9f1a
8fbc71a2912a8b12b426ebc97ca49c738cd22749
00ac71165014d9f3fc30345bb70017e4c786d72d
e261f601b14d68defc1ccf81119ecc50ea5d1ea9
78896c0bcb9506c6b5b2184539ebeb909d326beb
244093d57c031d07b7d260f2c8b6c96552b13e9f
03abf4d48e38797557e47ead30b9cb84db75e208
2090c1e309332bcd6db61f3323f2f75915a4dca5
84e011be4e35292d7e378e17a36857395e63594c
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Back out 13 changesets (bug 1226443, bug 1227015) for a variety of serviceworker web-platform-test failures CLOSED TREE Backed out changeset d518261eb3b1 (bug 1226443) Backed out changeset a7def186c1d3 (bug 1226443) Backed out changeset e2f21ee1cd4c (bug 1226443) Backed out changeset 8c4aff8bbfaf (bug 1226443) Backed out changeset 4c85bf5e9bf5 (bug 1226443) Backed out changeset 8fbc71a2912a (bug 1227015) Backed out changeset 00ac71165014 (bug 1227015) Backed out changeset e261f601b14d (bug 1227015) Backed out changeset 78896c0bcb95 (bug 1227015) Backed out changeset 244093d57c03 (bug 1227015) Backed out changeset 03abf4d48e38 (bug 1227015) Backed out changeset 2090c1e30933 (bug 1227015) Backed out changeset 84e011be4e35 (bug 1227015)
dom/base/nsDocument.cpp
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManager.h
dom/workers/ServiceWorkerPrivate.cpp
dom/workers/ServiceWorkerRegistration.cpp
dom/workers/ServiceWorkerScriptCache.cpp
dom/workers/test/serviceworkers/test_serviceworkerregistrationinfo.xul
testing/web-platform/mozilla/meta/service-workers/service-worker/update-after-navigation-fetch-event.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/update-after-oneday.https.html.ini
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -5045,24 +5045,16 @@ nsDocument::DispatchContentLoadedEvents(
   // event.
   Element* root = GetRootElement();
   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::manifest)) {
     nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
                                         NS_LITERAL_STRING("MozApplicationManifest"),
                                         true, true);
   }
 
-  if (mMaybeServiceWorkerControlled) {
-    using mozilla::dom::workers::ServiceWorkerManager;
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    if (swm) {
-      swm->MaybeCheckNavigationUpdate(this);
-    }
-  }
-
   UnblockOnload(true);
 }
 
 void
 nsDocument::EndLoad()
 {
   // Drop the ref to our parser, if any, but keep hold of the sink so that we
   // can flush it from FlushPendingNotifications as needed.  We might have to
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -16,17 +16,16 @@
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIJARChannel.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIMutableArray.h"
 #include "nsIScriptError.h"
 #include "nsISimpleEnumerator.h"
-#include "nsITimer.h"
 #include "nsIUploadChannel2.h"
 #include "nsPIDOMWindow.h"
 #include "nsScriptLoader.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDebug.h"
 #include "nsISupportsPrimitives.h"
 
 #include "jsapi.h"
@@ -131,19 +130,16 @@ struct ServiceWorkerManager::Registratio
   nsTArray<nsCString> mOrderedScopes;
 
   // Scope to registration.
   // The scope should be a fully qualified valid URL.
   nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistrationInfo> mInfos;
 
   // Maps scopes to job queues.
   nsClassHashtable<nsCStringHashKey, ServiceWorkerJobQueue> mJobQueues;
-
-  // Map scopes to scheduled update timers.
-  nsInterfaceHashtable<nsCStringHashKey, nsITimer> mUpdateTimers;
 };
 
 struct ServiceWorkerManager::PendingOperation final
 {
   nsCOMPtr<nsIRunnable> mRunnable;
 
   ServiceWorkerJobQueue* mQueue;
   RefPtr<ServiceWorkerJob> mJob;
@@ -317,23 +313,17 @@ PopulateRegistrationData(nsIPrincipal* a
   }
 
   nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &aData.principal());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   aData.scope() = aRegistration->mScope;
-
-  RefPtr<ServiceWorkerInfo> newest = aRegistration->Newest();
-  if (NS_WARN_IF(!newest)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  aData.scriptSpec() = newest->ScriptSpec();
+  aData.scriptSpec() = aRegistration->mScriptSpec;
 
   if (aRegistration->mActiveWorker) {
     aData.currentWorkerURL() = aRegistration->mActiveWorker->ScriptSpec();
     aData.activeCacheName() = aRegistration->mActiveWorker->CacheName();
   }
 
   if (aRegistration->mWaitingWorker) {
     aData.waitingCacheName() = aRegistration->mWaitingWorker->CacheName();
@@ -427,20 +417,19 @@ ServiceWorkerRegistrationInfo::Clear()
                                                  WhichServiceWorker::INSTALLING_WORKER |
                                                  WhichServiceWorker::WAITING_WORKER |
                                                  WhichServiceWorker::ACTIVE_WORKER);
 }
 
 ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope,
                                                              nsIPrincipal* aPrincipal)
   : mControlledDocumentsCounter(0)
-  , mUpdateState(NoUpdate)
-  , mLastUpdateCheckTime(0)
   , mScope(aScope)
   , mPrincipal(aPrincipal)
+  , mLastUpdateCheckTime(0)
   , mUpdating(false)
   , mPendingUninstall(false)
 {}
 
 ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
 {
   if (IsControllingDocuments()) {
     NS_WARNING("ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive.");
@@ -464,20 +453,17 @@ ServiceWorkerRegistrationInfo::GetScope(
   CopyUTF8toUTF16(mScope, aScope);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerRegistrationInfo::GetScriptSpec(nsAString& aScriptSpec)
 {
   AssertIsOnMainThread();
-  RefPtr<ServiceWorkerInfo> newest = Newest();
-  if (newest) {
-    CopyUTF8toUTF16(newest->ScriptSpec(), aScriptSpec);
-  }
+  CopyUTF8toUTF16(mScriptSpec, aScriptSpec);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerRegistrationInfo::GetInstallingWorker(nsIServiceWorkerInfo **aResult)
 {
   AssertIsOnMainThread();
   nsCOMPtr<nsIServiceWorkerInfo> info = do_QueryInterface(mInstallingWorker);
@@ -961,52 +947,22 @@ protected:
   RefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
   bool mCanceled;
   RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
   RefPtr<ServiceWorkerInfo> mUpdateAndInstallInfo;
 
   ~ServiceWorkerJobBase()
   { }
 
-  void
-  Succeed()
-  {
-    AssertIsOnMainThread();
-    // We don't have a callback for soft updates.
-    if (mCallback) {
-      mCallback->UpdateSucceeded(mRegistration);
-      mCallback = nullptr;
-    }
-  }
-};
-
-// Base type for jobs that work with a specific service worker script.
-class ServiceWorkerScriptJobBase : public ServiceWorkerJobBase
-{
-protected:
-  const nsCString mScriptSpec;
-
-  ServiceWorkerScriptJobBase(ServiceWorkerJobQueue* aQueue,
-                             ServiceWorkerJob::Type aJobType,
-                             ServiceWorkerUpdateFinishCallback* aCallback,
-                             ServiceWorkerRegistrationInfo* aRegistration,
-                             ServiceWorkerInfo* aServiceWorkerInfo,
-                             const nsACString& aScriptSpec)
-    : ServiceWorkerJobBase(aQueue, aJobType, aCallback, aRegistration,
-                           aServiceWorkerInfo)
-    , mScriptSpec(aScriptSpec)
-  {
-  }
-
   // This MUST only be called when the job is still performing actions related
   // to registration or update. After the spec resolves the update promise, use
   // Done() with the failure code instead.
   // Callers MUST hold a strong ref before calling this!
   void
-  FailWithErrorResult(ErrorResult& aRv)
+  Fail(ErrorResult& aRv)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(mRegistration);
 
     // With cancellation support, we may only be running with one reference
     // from another object like a stream loader or something.
     RefPtr<ServiceWorkerJob> kungFuDeathGrip = this;
 
@@ -1016,17 +972,17 @@ protected:
 
     // Ensure that we only surface SecurityErr or TypeErr to script.
     if (aRv.Failed() && !aRv.ErrorCodeIs(NS_ERROR_DOM_SECURITY_ERR) &&
                         !aRv.ErrorCodeIs(NS_ERROR_DOM_TYPE_ERR)) {
 
       // Remove the old error code so we can replace it with a TypeError.
       aRv.SuppressException();
 
-      NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
+      NS_ConvertUTF8toUTF16 scriptSpec(mRegistration->mScriptSpec);
       NS_ConvertUTF8toUTF16 scope(mRegistration->mScope);
 
       // Throw the type error with a generic error message.
       aRv.ThrowTypeError<MSG_SW_INSTALL_ERROR>(scriptSpec, scope);
     }
 
     if (mCallback) {
       mCallback->UpdateFailed(aRv);
@@ -1050,33 +1006,42 @@ protected:
     mRegistration = nullptr;
     Done(origStatus);
   }
 
   void
   Fail(nsresult aRv)
   {
     ErrorResult rv(aRv);
-    FailWithErrorResult(rv);
+    Fail(rv);
+  }
+
+  void
+  Succeed()
+  {
+    AssertIsOnMainThread();
+    // We don't have a callback for soft updates.
+    if (mCallback) {
+      mCallback->UpdateSucceeded(mRegistration);
+      mCallback = nullptr;
+    }
   }
 };
 
-class ServiceWorkerInstallJob final : public ServiceWorkerScriptJobBase
+class ServiceWorkerInstallJob final : public ServiceWorkerJobBase
 {
   friend class ContinueInstallTask;
 
 public:
   ServiceWorkerInstallJob(ServiceWorkerJobQueue* aQueue,
                           ServiceWorkerUpdateFinishCallback* aCallback,
                           ServiceWorkerRegistrationInfo* aRegistration,
-                          ServiceWorkerInfo* aServiceWorkerInfo,
-                          const nsACString& aScriptSpec)
-    : ServiceWorkerScriptJobBase(aQueue, Type::InstallJob, aCallback,
-                                 aRegistration, aServiceWorkerInfo,
-                                 aScriptSpec)
+                          ServiceWorkerInfo* aServiceWorkerInfo)
+    : ServiceWorkerJobBase(aQueue, Type::InstallJob, aCallback,
+                           aRegistration, aServiceWorkerInfo)
   {
     MOZ_ASSERT(aRegistration);
   }
 
   void
   Start()
   {
     AssertIsOnMainThread();
@@ -1191,56 +1156,56 @@ public:
     }
 
     Done(NS_OK);
     // Activate() is invoked out of band of atomic.
     mRegistration->TryToActivate();
   }
 };
 
-class ServiceWorkerRegisterJob final : public ServiceWorkerScriptJobBase,
+class ServiceWorkerRegisterJob final : public ServiceWorkerJobBase,
                                        public serviceWorkerScriptCache::CompareCallback
 {
   friend class ContinueUpdateRunnable;
 
   nsCString mScope;
+  nsCString mScriptSpec;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
 
   ~ServiceWorkerRegisterJob()
   { }
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // [[Register]]
   ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
                            const nsCString& aScope,
                            const nsCString& aScriptSpec,
                            ServiceWorkerUpdateFinishCallback* aCallback,
                            nsIPrincipal* aPrincipal,
                            nsILoadGroup* aLoadGroup)
-    : ServiceWorkerScriptJobBase(aQueue, Type::RegisterJob, aCallback, nullptr,
-                                 nullptr, aScriptSpec)
+    : ServiceWorkerJobBase(aQueue, Type::RegisterJob, aCallback)
     , mScope(aScope)
+    , mScriptSpec(aScriptSpec)
     , mPrincipal(aPrincipal)
     , mLoadGroup(aLoadGroup)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(mLoadGroup);
     MOZ_ASSERT(aCallback);
   }
 
   // [[Update]]
   ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
                            ServiceWorkerRegistrationInfo* aRegistration,
-                           ServiceWorkerUpdateFinishCallback* aCallback,
-                           const nsACString& aScriptSpec)
-    : ServiceWorkerScriptJobBase(aQueue, Type::UpdateJob, aCallback,
-                                 aRegistration, nullptr, aScriptSpec)
+                           ServiceWorkerUpdateFinishCallback* aCallback)
+    : ServiceWorkerJobBase(aQueue, Type::UpdateJob, aCallback,
+                           aRegistration, nullptr)
   {
     AssertIsOnMainThread();
   }
 
   void
   Start() override
   {
     AssertIsOnMainThread();
@@ -1255,17 +1220,18 @@ public:
     }
 
     if (mJobType == RegisterJob) {
       mRegistration = swm->GetRegistration(mPrincipal, mScope);
 
       if (mRegistration) {
         mRegistration->mPendingUninstall = false;
         RefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
-        if (newest && mScriptSpec.Equals(newest->ScriptSpec())) {
+        if (newest && mScriptSpec.Equals(newest->ScriptSpec()) &&
+            mScriptSpec.Equals(mRegistration->mScriptSpec)) {
           swm->StoreRegistration(mPrincipal, mRegistration);
           Succeed();
 
           // Done() must always be called async from Start()
           nsCOMPtr<nsIRunnable> runnable =
             NS_NewRunnableMethodWithArg<nsresult>(
               this,
               &ServiceWorkerRegisterJob::Done,
@@ -1273,35 +1239,21 @@ public:
           MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
 
           return;
         }
       } else {
         mRegistration = swm->CreateNewRegistration(mScope, mPrincipal);
       }
 
+      mRegistration->mScriptSpec = mScriptSpec;
+      mRegistration->NotifyListenersOnChange();
       swm->StoreRegistration(mPrincipal, mRegistration);
     } else {
       MOZ_ASSERT(mJobType == UpdateJob);
-
-      // If a different script spec has been registered between when this update
-      // was scheduled and it running now, then simply abort.
-      RefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
-      if (newest && !mScriptSpec.Equals(newest->ScriptSpec())) {
-
-        // Done() must always be called async from Start()
-        nsCOMPtr<nsIRunnable> runnable =
-          NS_NewRunnableMethodWithArg<nsresult>(
-            this,
-            &ServiceWorkerRegisterJob::Fail,
-            NS_ERROR_DOM_ABORT_ERR);
-          MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
-
-        return;
-      }
     }
 
     Update();
   }
 
   void
   ComparisonResult(nsresult aStatus, bool aInCacheAndEqual,
                    const nsAString& aNewCacheName,
@@ -1325,17 +1277,17 @@ public:
     }
 
     AssertIsOnMainThread();
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1);
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 
     nsCOMPtr<nsIURI> scriptURI;
-    nsresult rv = NS_NewURI(getter_AddRefs(scriptURI), mScriptSpec);
+    nsresult rv = NS_NewURI(getter_AddRefs(scriptURI), mRegistration->mScriptSpec);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       Fail(NS_ERROR_DOM_SECURITY_ERR);
       return;
     }
     nsCOMPtr<nsIURI> maxScopeURI;
     if (!aMaxScope.IsEmpty()) {
       rv = NS_NewURI(getter_AddRefs(maxScopeURI), aMaxScope,
                      nullptr, scriptURI);
@@ -1375,17 +1327,18 @@ public:
 
     ServiceWorkerManager::RegistrationDataPerPrincipal* data;
     if (!swm->mRegistrationInfos.Get(scopeKey, &data)) {
       return Fail(NS_ERROR_FAILURE);
     }
 
     MOZ_ASSERT(!mUpdateAndInstallInfo);
     mUpdateAndInstallInfo =
-      new ServiceWorkerInfo(mRegistration, mScriptSpec, aNewCacheName);
+      new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec,
+                            aNewCacheName);
 
     RefPtr<ServiceWorkerJob> upcasted = this;
     nsMainThreadPtrHandle<nsISupports> handle(
         new nsMainThreadPtrHolder<nsISupports>(upcasted));
     RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle);
 
     ServiceWorkerPrivate* workerPrivate =
       mUpdateAndInstallInfo->WorkerPrivate();
@@ -1409,25 +1362,25 @@ private:
     RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
     if (mCanceled) {
       return Fail(NS_ERROR_DOM_ABORT_ERR);
     }
 
     if (NS_WARN_IF(!aScriptEvaluationResult)) {
       ErrorResult error;
 
-      NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
+      NS_ConvertUTF8toUTF16 scriptSpec(mRegistration->mScriptSpec);
       NS_ConvertUTF8toUTF16 scope(mRegistration->mScope);
       error.ThrowTypeError<MSG_SW_SCRIPT_THREW>(scriptSpec, scope);
-      return FailWithErrorResult(error);
+      return Fail(error);
     }
 
     RefPtr<ServiceWorkerInstallJob> job =
-      new ServiceWorkerInstallJob(mQueue, mCallback, mRegistration,
-                                  mUpdateAndInstallInfo, mScriptSpec);
+      new ServiceWorkerInstallJob(mQueue, mCallback,
+                                  mRegistration, mUpdateAndInstallInfo);
     mQueue->Append(job);
     Done(NS_OK);
   }
 
   void
   Update()
   {
     AssertIsOnMainThread();
@@ -1460,24 +1413,24 @@ private:
     }
 
     RefPtr<ServiceWorkerInfo> workerInfo = mRegistration->Newest();
     nsAutoString cacheName;
 
     // 9.2.20 If newestWorker is not null, and newestWorker's script url is
     // equal to registration's registering script url and response is a
     // byte-for-byte match with the script resource of newestWorker...
-    if (workerInfo && workerInfo->ScriptSpec().Equals(mScriptSpec)) {
+    if (workerInfo && workerInfo->ScriptSpec().Equals(mRegistration->mScriptSpec)) {
       cacheName = workerInfo->CacheName();
     }
 
     nsresult rv =
       serviceWorkerScriptCache::Compare(mRegistration, mRegistration->mPrincipal, cacheName,
-                                        NS_ConvertUTF8toUTF16(mScriptSpec), this,
-                                        mLoadGroup);
+                                        NS_ConvertUTF8toUTF16(mRegistration->mScriptSpec),
+                                        this, mLoadGroup);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return Fail(rv);
     }
   }
 
   void
   Done(nsresult aStatus)
   {
@@ -2741,87 +2694,38 @@ ServiceWorkerRegistrationInfo::NotifyLis
 {
   nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> listeners(mListeners);
   for (size_t index = 0; index < listeners.Length(); ++index) {
     listeners[index]->OnChange();
   }
 }
 
 void
-ServiceWorkerRegistrationInfo::MaybeScheduleTimeCheckAndUpdate()
-{
-  AssertIsOnMainThread();
-
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  if (!swm) {
-    // shutting down, do nothing
-    return;
-  }
-
-  if (mUpdateState == NoUpdate) {
-    mUpdateState = NeedTimeCheckAndUpdate;
-  }
-
-  swm->ScheduleUpdateTimer(mPrincipal, mScope);
-}
-
-void
-ServiceWorkerRegistrationInfo::MaybeScheduleUpdate()
-{
-  AssertIsOnMainThread();
-
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  if (!swm) {
-    // shutting down, do nothing
-    return;
-  }
-
-  mUpdateState = NeedUpdate;
-
-  swm->ScheduleUpdateTimer(mPrincipal, mScope);
-}
-
-bool
-ServiceWorkerRegistrationInfo::CheckAndClearIfUpdateNeeded()
-{
-  AssertIsOnMainThread();
-
-  bool result = mUpdateState == NeedUpdate ||
-               (mUpdateState == NeedTimeCheckAndUpdate &&
-                IsLastUpdateCheckTimeOverOneDay());
-
-  mUpdateState = NoUpdate;
-
-  return result;
-}
-
-void
 ServiceWorkerManager::LoadRegistration(
                              const ServiceWorkerRegistrationData& aRegistration)
 {
   AssertIsOnMainThread();
 
   nsCOMPtr<nsIPrincipal> principal =
     PrincipalInfoToPrincipal(aRegistration.principal());
   if (!principal) {
     return;
   }
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetRegistration(principal, aRegistration.scope());
   if (!registration) {
     registration = CreateNewRegistration(aRegistration.scope(), principal);
-  } else {
-    RefPtr<ServiceWorkerInfo> newest = registration->Newest();
-    if (newest && newest->ScriptSpec() == aRegistration.scriptSpec() &&
-        !!registration->mActiveWorker == aRegistration.currentWorkerURL().IsEmpty()) {
-      // No needs for updates.
-      return;
-    }
-  }
+  } else if (registration->mScriptSpec == aRegistration.scriptSpec() &&
+             !!registration->mActiveWorker == aRegistration.currentWorkerURL().IsEmpty()) {
+    // No needs for updates.
+    return;
+  }
+
+  registration->mScriptSpec = aRegistration.scriptSpec();
 
   const nsCString& currentWorkerURL = aRegistration.currentWorkerURL();
   if (!currentWorkerURL.IsEmpty()) {
     registration->mActiveWorker =
       new ServiceWorkerInfo(registration, currentWorkerURL,
                             aRegistration.activeCacheName());
     registration->mActiveWorker->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
   }
@@ -3115,22 +3019,16 @@ ServiceWorkerManager::RemoveScopeAndRegi
     return;
   }
 
   RegistrationDataPerPrincipal* data;
   if (!swm->mRegistrationInfos.Get(scopeKey, &data)) {
     return;
   }
 
-  nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aRegistration->mScope);
-  if (timer) {
-    timer->Cancel();
-    data->mUpdateTimers.Remove(aRegistration->mScope);
-  }
-
   RefPtr<ServiceWorkerRegistrationInfo> info;
   data->mInfos.Get(aRegistration->mScope, getter_AddRefs(info));
 
   data->mInfos.Remove(aRegistration->mScope);
   data->mOrderedScopes.RemoveElement(aRegistration->mScope);
   swm->NotifyListenersOnUnregister(info);
 
   swm->MaybeRemoveRegistrationInfo(scopeKey);
@@ -3181,37 +3079,16 @@ ServiceWorkerManager::MaybeStopControlli
   if (registration) {
     StopControllingADocument(registration);
   }
 
   mAllDocuments.RemoveEntry(aDoc);
 }
 
 void
-ServiceWorkerManager::MaybeCheckNavigationUpdate(nsIDocument* aDoc)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aDoc);
-  // We perform these success path navigation update steps when the
-  // document tells us its more or less done loading.  This avoids
-  // slowing down page load and also lets pages consistently get
-  // updatefound events when they fire.
-  //
-  // 9.8.20 If respondWithEntered is false, then:
-  // 9.8.22 Else: (respondWith was entered and succeeded)
-  //    If request is a non-subresource request, then: Invoke Soft Update
-  //    algorithm.
-  RefPtr<ServiceWorkerRegistrationInfo> registration;
-  mControlledDocuments.Get(aDoc, getter_AddRefs(registration));
-  if (registration) {
-    registration->MaybeScheduleUpdate();
-  }
-}
-
-void
 ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
                                                 nsIDocument* aDoc,
                                                 const nsAString& aDocumentId)
 {
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(aDoc);
 
   aRegistration->StartControllingADocument();
@@ -3724,27 +3601,29 @@ ServiceWorkerManager::SoftUpdate(const O
   // "Let newestWorker be the result of running Get Newest Worker algorithm
   // passing registration as its argument.
   // If newestWorker is null, abort these steps."
   RefPtr<ServiceWorkerInfo> newest = registration->Newest();
   if (!newest) {
     return;
   }
 
+  // "Set registration's registering script url to newestWorker's script url."
+  registration->mScriptSpec = newest->ScriptSpec();
+
   // "If the registration queue for registration is empty, invoke Update algorithm,
   // or its equivalent, with client, registration as its argument."
   // TODO(catalinb): We don't implement the force bypass cache flag.
   // See: https://github.com/slightlyoff/ServiceWorker/issues/759
   if (!registration->mUpdating) {
     ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scopeKey, aScope);
     MOZ_ASSERT(queue);
 
     RefPtr<ServiceWorkerRegisterJob> job =
-      new ServiceWorkerRegisterJob(queue, registration, nullptr,
-                                   newest->ScriptSpec());
+      new ServiceWorkerRegisterJob(queue, registration, nullptr);
     queue->Append(job);
   }
 }
 
 void
 ServiceWorkerManager::Update(nsIPrincipal* aPrincipal,
                              const nsACString& aScope,
                              ServiceWorkerUpdateFinishCallback* aCallback)
@@ -3778,25 +3657,27 @@ ServiceWorkerManager::Update(nsIPrincipa
     aCallback->UpdateFailed(error);
 
     // In case the callback does not consume the exception
     error.SuppressException();
 
     return;
   }
 
+  // "Set registration's registering script url to newestWorker's script url."
+  registration->mScriptSpec = newest->ScriptSpec();
+
   ServiceWorkerJobQueue* queue =
     GetOrCreateJobQueue(scopeKey, aScope);
   MOZ_ASSERT(queue);
 
   // "Invoke Update algorithm, or its equivalent, with client, registration as
   // its argument."
   RefPtr<ServiceWorkerRegisterJob> job =
-    new ServiceWorkerRegisterJob(queue, registration, aCallback,
-                                 newest->ScriptSpec());
+    new ServiceWorkerRegisterJob(queue, registration, aCallback);
   queue->Append(job);
 }
 
 namespace {
 
 static void
 FireControllerChangeOnDocument(nsIDocument* aDocument)
 {
@@ -4237,23 +4118,16 @@ ServiceWorkerManager::ForceUnregister(Re
   MOZ_ASSERT(aRegistration);
 
   ServiceWorkerJobQueue* queue;
   aRegistrationData->mJobQueues.Get(aRegistration->mScope, &queue);
   if (queue) {
     queue->CancelJobs();
   }
 
-  nsCOMPtr<nsITimer> timer =
-    aRegistrationData->mUpdateTimers.Get(aRegistration->mScope);
-  if (timer) {
-    timer->Cancel();
-    aRegistrationData->mUpdateTimers.Remove(aRegistration->mScope);
-  }
-
   // Since Unregister is async, it is ok to call it in an enumeration.
   Unregister(aRegistration->mPrincipal, nullptr, NS_ConvertUTF8toUTF16(aRegistration->mScope));
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::RemoveAndPropagate(const nsACString& aHost)
 {
   Remove(aHost);
@@ -4573,24 +4447,16 @@ ServiceWorkerManager::Observe(nsISupport
 
     RemoveAllRegistrations(&attrs);
     return NS_OK;
   }
 
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
     mShuttingDown = true;
 
-    for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
-      for (auto it2 = it1.UserData()->mUpdateTimers.Iter(); !it2.Done(); it2.Next()) {
-        nsCOMPtr<nsITimer> timer = it2.UserData();
-        timer->Cancel();
-      }
-      it1.UserData()->mUpdateTimers.Clear();
-    }
-
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
 
       if (XRE_IsParentProcess()) {
         obs->RemoveObserver(this, PURGE_SESSION_HISTORY);
         obs->RemoveObserver(this, PURGE_DOMAIN_DATA);
         obs->RemoveObserver(this, CLEAR_ORIGIN_DATA);
@@ -4785,153 +4651,16 @@ ServiceWorkerManager::RemoveNavigationIn
     if (list->IsEmpty()) {
       list = nullptr;
       nsAutoPtr<InterceptionList> doomed;
       mNavigationInterceptions.RemoveAndForget(aScope, doomed);
     }
   }
 }
 
-class UpdateTimerCallback final : public nsITimerCallback
-{
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-  const nsCString mScope;
-
-  ~UpdateTimerCallback()
-  {
-  }
-
-public:
-  UpdateTimerCallback(nsIPrincipal* aPrincipal, const nsACString& aScope)
-    : mPrincipal(aPrincipal)
-    , mScope(aScope)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(mPrincipal);
-    MOZ_ASSERT(!mScope.IsEmpty());
-  }
-
-  NS_IMETHOD
-  Notify(nsITimer* aTimer) override
-  {
-    AssertIsOnMainThread();
-
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    if (!swm) {
-      // shutting down, do nothing
-      return NS_OK;
-    }
-
-    swm->UpdateTimerFired(mPrincipal, mScope);
-    return NS_OK;
-  }
-
-  NS_DECL_ISUPPORTS
-};
-
-NS_IMPL_ISUPPORTS(UpdateTimerCallback, nsITimerCallback)
-
-void
-ServiceWorkerManager::ScheduleUpdateTimer(nsIPrincipal* aPrincipal,
-                                          const nsACString& aScope)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aPrincipal);
-  MOZ_ASSERT(!aScope.IsEmpty());
-
-  if (mShuttingDown) {
-    return;
-  }
-
-  nsAutoCString scopeKey;
-  nsresult rv = PrincipalToScopeKey(aPrincipal, scopeKey);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  RegistrationDataPerPrincipal* data;
-  if (!mRegistrationInfos.Get(scopeKey, &data)) {
-    return;
-  }
-
-  nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aScope);
-  if (timer) {
-    // There is already a timer scheduled.  In this case just use the original
-    // schedule time.  We don't want to push it out to a later time since that
-    // could allow updates to be starved forever if events are continuously
-    // fired.
-    return;
-  }
-
-  timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  nsCOMPtr<nsITimerCallback> callback = new UpdateTimerCallback(aPrincipal,
-                                                                aScope);
-
-  const uint32_t UPDATE_DELAY_MS = 1000;
-
-  rv = timer->InitWithCallback(callback, UPDATE_DELAY_MS,
-                               nsITimer::TYPE_ONE_SHOT);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  data->mUpdateTimers.Put(aScope, timer);
-}
-
-void
-ServiceWorkerManager::UpdateTimerFired(nsIPrincipal* aPrincipal,
-                                       const nsACString& aScope)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aPrincipal);
-  MOZ_ASSERT(!aScope.IsEmpty());
-
-  if (mShuttingDown) {
-    return;
-  }
-
-  // First cleanup the timer.
-  nsAutoCString scopeKey;
-  nsresult rv = PrincipalToScopeKey(aPrincipal, scopeKey);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  RegistrationDataPerPrincipal* data;
-  if (!mRegistrationInfos.Get(scopeKey, &data)) {
-    return;
-  }
-
-  nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aScope);
-  if (timer) {
-    timer->Cancel();
-    data->mUpdateTimers.Remove(aScope);
-  }
-
-  RefPtr<ServiceWorkerRegistrationInfo> registration;
-  data->mInfos.Get(aScope, getter_AddRefs(registration));
-  if (!registration) {
-    return;
-  }
-
-  if (!registration->CheckAndClearIfUpdateNeeded()) {
-    return;
-  }
-
-  PrincipalOriginAttributes attrs =
-    mozilla::BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
-
-  // Then trigger an update to fire asynchronously now.
-  PropagateSoftUpdate(attrs, NS_ConvertUTF8toUTF16(aScope));
-}
-
 NS_IMPL_ISUPPORTS(ServiceWorkerInfo, nsIServiceWorkerInfo)
 
 NS_IMETHODIMP
 ServiceWorkerInfo::GetScriptSpec(nsAString& aScriptSpec)
 {
   AssertIsOnMainThread();
   CopyUTF8toUTF16(mScriptSpec, aScriptSpec);
   return NS_OK;
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -52,57 +52,53 @@ class ServiceWorkerJobQueue;
 class ServiceWorkerManagerChild;
 class ServiceWorkerPrivate;
 
 class ServiceWorkerRegistrationInfo final
   : public nsIServiceWorkerRegistrationInfo
 {
   uint32_t mControlledDocumentsCounter;
 
-  enum
-  {
-    NoUpdate,
-    NeedTimeCheckAndUpdate,
-    NeedUpdate
-  } mUpdateState;
-
-  uint64_t mLastUpdateCheckTime;
-
   virtual ~ServiceWorkerRegistrationInfo();
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERREGISTRATIONINFO
 
   nsCString mScope;
+  // The scriptURL for the registration. This may be completely different from
+  // the URLs of the following three workers.
+  nsCString mScriptSpec;
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
   RefPtr<ServiceWorkerInfo> mActiveWorker;
   RefPtr<ServiceWorkerInfo> mWaitingWorker;
   RefPtr<ServiceWorkerInfo> mInstallingWorker;
 
   nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> mListeners;
 
+  uint64_t mLastUpdateCheckTime;
+
   // According to the spec, Soft Update shouldn't queue an update job
   // if the registration queue is not empty. Because our job queue
   // works slightly different, we use a flag to determine if the registration
   // is already updating.
   bool mUpdating;
 
   // When unregister() is called on a registration, it is not immediately
   // removed since documents may be controlled. It is marked as
   // pendingUninstall and when all controlling documents go away, removed.
   bool mPendingUninstall;
 
   ServiceWorkerRegistrationInfo(const nsACString& aScope,
                                 nsIPrincipal* aPrincipal);
 
   already_AddRefed<ServiceWorkerInfo>
-  Newest() const
+  Newest()
   {
     RefPtr<ServiceWorkerInfo> newest;
     if (mInstallingWorker) {
       newest = mInstallingWorker;
     } else if (mWaitingWorker) {
       newest = mWaitingWorker;
     } else {
       newest = mActiveWorker;
@@ -151,25 +147,16 @@ public:
   void
   RefreshLastUpdateCheckTime();
 
   bool
   IsLastUpdateCheckTimeOverOneDay() const;
 
   void
   NotifyListenersOnChange();
-
-  void
-  MaybeScheduleTimeCheckAndUpdate();
-
-  void
-  MaybeScheduleUpdate();
-
-  bool
-  CheckAndClearIfUpdateNeeded();
 };
 
 class ServiceWorkerUpdateFinishCallback
 {
 protected:
   virtual ~ServiceWorkerUpdateFinishCallback()
   {}
 
@@ -324,20 +311,18 @@ class ServiceWorkerManager final
 {
   friend class GetReadyPromiseRunnable;
   friend class GetRegistrationsRunnable;
   friend class GetRegistrationRunnable;
   friend class ServiceWorkerJobQueue;
   friend class ServiceWorkerInstallJob;
   friend class ServiceWorkerRegisterJob;
   friend class ServiceWorkerJobBase;
-  friend class ServiceWorkerScriptJobBase;
   friend class ServiceWorkerRegistrationInfo;
   friend class ServiceWorkerUnregisterJob;
-  friend class UpdateTimerCallback;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERMANAGER
   NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
   NS_DECL_NSIOBSERVER
 
   struct RegistrationDataPerPrincipal;
@@ -490,20 +475,16 @@ public:
 
   NS_IMETHOD
   AddRegistrationEventListener(const nsAString& aScope,
                                ServiceWorkerRegistrationListener* aListener);
 
   NS_IMETHOD
   RemoveRegistrationEventListener(const nsAString& aScope,
                                   ServiceWorkerRegistrationListener* aListener);
-
-  void
-  MaybeCheckNavigationUpdate(nsIDocument* aDoc);
-
 private:
   ServiceWorkerManager();
   ~ServiceWorkerManager();
 
   void
   Init();
 
   ServiceWorkerJobQueue*
@@ -672,21 +653,15 @@ private:
 
   void
   AddNavigationInterception(const nsACString& aScope,
                             nsIInterceptedChannel* aChannel);
 
   void
   RemoveNavigationInterception(const nsACString& aScope,
                                nsIInterceptedChannel* aChannel);
-
-  void
-  ScheduleUpdateTimer(nsIPrincipal* aPrincipal, const nsACString& aScope);
-
-  void
-  UpdateTimerFired(nsIPrincipal* aPrincipal, const nsACString& aScope);
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworkermanager_h
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -207,36 +207,56 @@ public:
     MOZ_ASSERT(workerPrivate);
     workerPrivate->AssertIsOnWorkerThread();
 #endif
   }
 };
 
 NS_IMPL_ISUPPORTS0(KeepAliveHandler)
 
-class RegistrationUpdateRunnable : public nsRunnable
+class SoftUpdateRequest : public nsRunnable
 {
+protected:
   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-  const bool mNeedTimeCheck;
-
 public:
-  RegistrationUpdateRunnable(nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
-                             bool aNeedTimeCheck)
+  explicit SoftUpdateRequest(nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
     : mRegistration(aRegistration)
-    , mNeedTimeCheck(aNeedTimeCheck)
   {
+    MOZ_ASSERT(aRegistration);
   }
 
-  NS_IMETHOD
-  Run() override
+  NS_IMETHOD Run()
   {
-    if (mNeedTimeCheck) {
-      mRegistration->MaybeScheduleTimeCheckAndUpdate();
-    } else {
-      mRegistration->MaybeScheduleUpdate();
+    AssertIsOnMainThread();
+
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    MOZ_ASSERT(swm);
+
+    PrincipalOriginAttributes attrs =
+      mozilla::BasePrincipal::Cast(mRegistration->mPrincipal)->OriginAttributesRef();
+
+    swm->PropagateSoftUpdate(attrs,
+                             NS_ConvertUTF8toUTF16(mRegistration->mScope));
+    return NS_OK;
+  }
+};
+
+class CheckLastUpdateTimeRequest final : public SoftUpdateRequest
+{
+public:
+  explicit CheckLastUpdateTimeRequest(
+    nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
+    : SoftUpdateRequest(aRegistration)
+  {}
+
+  NS_IMETHOD Run()
+  {
+    AssertIsOnMainThread();
+    if (mRegistration->IsLastUpdateCheckTimeOverOneDay()) {
+      SoftUpdateRequest::Run();
     }
     return NS_OK;
   }
 };
 
 class ExtendableEventWorkerRunnable : public WorkerRunnable
 {
 protected:
@@ -310,19 +330,19 @@ public:
     , mRegistration(aRegistration)
   {
     MOZ_ASSERT(aRegistration);
   }
 
   void
   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
   {
-    nsCOMPtr<nsIRunnable> runnable =
-      new RegistrationUpdateRunnable(mRegistration, true /* time check */);
-    NS_DispatchToMainThread(runnable.forget());
+    nsCOMPtr<nsIRunnable> runnable = new CheckLastUpdateTimeRequest(mRegistration);
+
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable.forget())));
   }
 };
 
 /*
  * Fires 'install' event on the ServiceWorkerGlobalScope. Modifies busy count
  * since it fires the event. This is ok since there can't be nested
  * ServiceWorkers, so the parent thread -> worker thread requirement for
  * runnables is satisfied.
@@ -1256,41 +1276,42 @@ private:
     event->SetTrusted(true);
 
     RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
     nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
     if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
       nsCOMPtr<nsIRunnable> runnable;
       if (event->DefaultPrevented(aCx)) {
         event->ReportCanceled();
+        runnable = new CancelChannelRunnable(mInterceptedChannel,
+                                             NS_ERROR_INTERCEPTION_FAILED);
       } else if (event->GetInternalNSEvent()->mFlags.mExceptionHasBeenRisen) {
         // Exception logged via the WorkerPrivate ErrorReporter
+        runnable = new CancelChannelRunnable(mInterceptedChannel,
+                                             NS_ERROR_INTERCEPTION_FAILED);
       } else {
         runnable = new ResumeRequest(mInterceptedChannel);
       }
 
-      if (!runnable) {
-        nsCOMPtr<nsIRunnable> updateRunnable =
-          new RegistrationUpdateRunnable(mRegistration, false /* time check */);
-        NS_DispatchToMainThread(runnable.forget());
-
-        runnable = new CancelChannelRunnable(mInterceptedChannel,
-                                             NS_ERROR_INTERCEPTION_FAILED);
-      }
-
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
     }
 
     RefPtr<Promise> waitUntilPromise = event->GetPromise();
     if (waitUntilPromise) {
       RefPtr<KeepAliveHandler> keepAliveHandler =
         new KeepAliveHandler(mKeepAliveToken);
       waitUntilPromise->AppendNativeHandler(keepAliveHandler);
     }
 
+    // 9.8.22 If request is a non-subresource request, then: Invoke Soft Update algorithm
+    if (internalReq->IsNavigationRequest()) {
+      nsCOMPtr<nsIRunnable> runnable= new SoftUpdateRequest(mRegistration);
+
+      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable.forget())));
+    }
     return true;
   }
 
   nsresult
   HandleBodyWithHeaders(nsIInputStream* aUploadStream)
   {
     // We are dealing with an nsMIMEInputStream which uses string input streams
     // under the hood, so all of the data is available synchronously.
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -332,25 +332,16 @@ public:
       promise->MaybeReject(mStatus);
     } else {
       promise->MaybeResolve(JS::UndefinedHandleValue);
     }
     mStatus.SuppressException();
     mPromiseProxy->CleanUp(aCx);
     return true;
   }
-
-  void
-  PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
-               bool aSuccess) override
-  {
-    if (!aSuccess) {
-      mStatus.SuppressException();
-    }
-  }
 };
 
 class WorkerThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
 {
   RefPtr<PromiseWorkerProxy> mPromiseProxy;
 
   ~WorkerThreadUpdateCallback()
   {
--- a/dom/workers/ServiceWorkerScriptCache.cpp
+++ b/dom/workers/ServiceWorkerScriptCache.cpp
@@ -258,33 +258,30 @@ public:
     // the cache even if there isn't an existing one.
     AutoJSAPI jsapi;
     jsapi.Init();
     ErrorResult result;
     mSandbox.init(jsapi.cx());
     mCacheStorage = CreateCacheStorage(jsapi.cx(), aPrincipal, result, &mSandbox);
     if (NS_WARN_IF(result.Failed())) {
       MOZ_ASSERT(!result.IsErrorWithMessage());
-      Cleanup();
       return result.StealNSResult();
     }
 
     mCN = new CompareNetwork(this);
     nsresult rv = mCN->Initialize(aPrincipal, aURL, aLoadGroup);
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      Cleanup();
       return rv;
     }
 
     if (!aCacheName.IsEmpty()) {
       mCC = new CompareCache(this);
       rv = mCC->Initialize(aPrincipal, aURL, aCacheName);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         mCN->Abort();
-        Cleanup();
         return rv;
       }
     }
 
     return NS_OK;
   }
 
   const nsAString&
--- a/dom/workers/test/serviceworkers/test_serviceworkerregistrationinfo.xul
+++ b/dom/workers/test/serviceworkers/test_serviceworkerregistrationinfo.xul
@@ -42,58 +42,63 @@
           promise = waitForRegister(EXAMPLE_URL, function (registration) {
             is(registration.scriptSpec, "");
             ok(registration.installingWorker === null);
             ok(registration.waitingWorker === null);
             ok(registration.activeWorker === null);
 
             return waitForServiceWorkerRegistrationChange(registration, function  () {
               is(registration.scriptSpec, EXAMPLE_URL + "worker.js");
+
+              return waitForServiceWorkerRegistrationChange(registration, function () {
+                ok(registration.installingWorker !== null);
+                ok(registration.waitingWorker === null);
+                ok(registration.activeWorker === null);
+
+                return waitForServiceWorkerRegistrationChange(registration, function () {
+                  ok(registration.installingWorker === null);
+                  ok(registration.waitingWorker !== null);
+                  ok(registration.activeWorker === null);
+
+                  return waitForServiceWorkerRegistrationChange(registration, function () {
+                    ok(registration.installingWorker === null);
+                    ok(registration.waitingWorker === null);
+                    ok(registration.activeWorker !== null);
+
+                    return registration;
+                  });
+                });
+              });
+            });
+          });
+          iframe.contentWindow.postMessage("register", "*");
+          let registration = yield promise;
+
+          promise = waitForServiceWorkerRegistrationChange(registration, function () {
+            is(registration.scriptSpec, EXAMPLE_URL + "worker2.js");
+
+            return waitForServiceWorkerRegistrationChange(registration, function () {
               ok(registration.installingWorker !== null);
-              is(registration.installingWorker.scriptSpec, EXAMPLE_URL + "worker.js");
               ok(registration.waitingWorker === null);
-              ok(registration.activeWorker === null);
+              ok(registration.activeWorker !== null);
 
               return waitForServiceWorkerRegistrationChange(registration, function () {
                 ok(registration.installingWorker === null);
                 ok(registration.waitingWorker !== null);
-                ok(registration.activeWorker === null);
+                ok(registration.activeWorker !== null);
 
                 return waitForServiceWorkerRegistrationChange(registration, function () {
                   ok(registration.installingWorker === null);
                   ok(registration.waitingWorker === null);
                   ok(registration.activeWorker !== null);
 
                   return registration;
                 });
               });
-            });
-          });
-          iframe.contentWindow.postMessage("register", "*");
-          let registration = yield promise;
 
-          promise = waitForServiceWorkerRegistrationChange(registration, function () {
-            is(registration.scriptSpec, EXAMPLE_URL + "worker2.js");
-            ok(registration.installingWorker !== null);
-            is(registration.installingWorker.scriptSpec, EXAMPLE_URL + "worker2.js");
-            ok(registration.waitingWorker === null);
-            ok(registration.activeWorker !== null);
-
-            return waitForServiceWorkerRegistrationChange(registration, function () {
-              ok(registration.installingWorker === null);
-              ok(registration.waitingWorker !== null);
-              ok(registration.activeWorker !== null);
-
-              return waitForServiceWorkerRegistrationChange(registration, function () {
-                ok(registration.installingWorker === null);
-                ok(registration.waitingWorker === null);
-                ok(registration.activeWorker !== null);
-
-                return registration;
-              });
             });
           });
           iframe.contentWindow.postMessage("register", "*");
           yield promise;
 
           SimpleTest.finish();
         });
       });
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/update-after-navigation-fetch-event.https.html.ini
@@ -0,0 +1,3 @@
+[update-after-navigation-fetch-event.https.html]
+  type: testharness
+  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1226443
--- a/testing/web-platform/mozilla/meta/service-workers/service-worker/update-after-oneday.https.html.ini
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/update-after-oneday.https.html.ini
@@ -1,3 +1,4 @@
 [update-after-oneday.https.html]
   type: testharness
   prefs: [dom.serviceWorkers.testUpdateOverOneDay: true]
+  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1226443