LCOV - code coverage report
Current view: top level - dom/workers - ServiceWorkerUpdateJob.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 246 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "ServiceWorkerUpdateJob.h"
       8             : 
       9             : #include "nsIScriptError.h"
      10             : #include "nsIURL.h"
      11             : #include "ServiceWorkerScriptCache.h"
      12             : #include "Workers.h"
      13             : 
      14             : namespace mozilla {
      15             : namespace dom {
      16             : namespace workers {
      17             : 
      18             : namespace {
      19             : 
      20             : /**
      21             :  * The spec mandates slightly different behaviors for computing the scope
      22             :  * prefix string in case a Service-Worker-Allowed header is specified versus
      23             :  * when it's not available.
      24             :  *
      25             :  * With the header:
      26             :  *   "Set maxScopeString to "/" concatenated with the strings in maxScope's
      27             :  *    path (including empty strings), separated from each other by "/"."
      28             :  * Without the header:
      29             :  *   "Set maxScopeString to "/" concatenated with the strings, except the last
      30             :  *    string that denotes the script's file name, in registration's registering
      31             :  *    script url's path (including empty strings), separated from each other by
      32             :  *    "/"."
      33             :  *
      34             :  * In simpler terms, if the header is not present, we should only use the
      35             :  * "directory" part of the pathname, and otherwise the entire pathname should be
      36             :  * used.  ScopeStringPrefixMode allows the caller to specify the desired
      37             :  * behavior.
      38             :  */
      39             : enum ScopeStringPrefixMode {
      40             :   eUseDirectory,
      41             :   eUsePath
      42             : };
      43             : 
      44             : nsresult
      45           0 : GetRequiredScopeStringPrefix(nsIURI* aScriptURI, nsACString& aPrefix,
      46             :                              ScopeStringPrefixMode aPrefixMode)
      47             : {
      48           0 :   nsresult rv = aScriptURI->GetPrePath(aPrefix);
      49           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
      50           0 :     return rv;
      51             :   }
      52             : 
      53           0 :   if (aPrefixMode == eUseDirectory) {
      54           0 :     nsCOMPtr<nsIURL> scriptURL(do_QueryInterface(aScriptURI));
      55           0 :     if (NS_WARN_IF(!scriptURL)) {
      56           0 :       return NS_ERROR_FAILURE;
      57             :     }
      58             : 
      59           0 :     nsAutoCString dir;
      60           0 :     rv = scriptURL->GetDirectory(dir);
      61           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
      62           0 :       return rv;
      63             :     }
      64             : 
      65           0 :     aPrefix.Append(dir);
      66           0 :   } else if (aPrefixMode == eUsePath) {
      67           0 :     nsAutoCString path;
      68           0 :     rv = aScriptURI->GetPath(path);
      69           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
      70           0 :       return rv;
      71             :     }
      72             : 
      73           0 :     aPrefix.Append(path);
      74             :   } else {
      75           0 :     MOZ_ASSERT_UNREACHABLE("Invalid value for aPrefixMode");
      76             :   }
      77           0 :   return NS_OK;
      78             : }
      79             : 
      80             : } // anonymous namespace
      81             : 
      82             : class ServiceWorkerUpdateJob::CompareCallback final : public serviceWorkerScriptCache::CompareCallback
      83             : {
      84             :   RefPtr<ServiceWorkerUpdateJob> mJob;
      85             : 
      86           0 :   ~CompareCallback()
      87           0 :   {
      88           0 :   }
      89             : 
      90             : public:
      91           0 :   explicit CompareCallback(ServiceWorkerUpdateJob* aJob)
      92           0 :     : mJob(aJob)
      93             :   {
      94           0 :     MOZ_ASSERT(mJob);
      95           0 :   }
      96             : 
      97             :   virtual void
      98           0 :   ComparisonResult(nsresult aStatus,
      99             :                    bool aInCacheAndEqual,
     100             :                    const nsAString& aNewCacheName,
     101             :                    const nsACString& aMaxScope,
     102             :                    nsLoadFlags aLoadFlags) override
     103             :   {
     104           0 :     mJob->ComparisonResult(aStatus,
     105             :                            aInCacheAndEqual,
     106             :                            aNewCacheName,
     107             :                            aMaxScope,
     108           0 :                            aLoadFlags);
     109           0 :   }
     110             : 
     111           0 :   NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateJob::CompareCallback, override)
     112             : };
     113             : 
     114           0 : class ServiceWorkerUpdateJob::ContinueUpdateRunnable final : public LifeCycleEventCallback
     115             : {
     116             :   nsMainThreadPtrHandle<ServiceWorkerUpdateJob> mJob;
     117             :   bool mSuccess;
     118             : 
     119             : public:
     120           0 :   explicit ContinueUpdateRunnable(const nsMainThreadPtrHandle<ServiceWorkerUpdateJob>& aJob)
     121           0 :     : mJob(aJob)
     122           0 :     , mSuccess(false)
     123             :   {
     124           0 :     AssertIsOnMainThread();
     125           0 :   }
     126             : 
     127             :   void
     128           0 :   SetResult(bool aResult) override
     129             :   {
     130           0 :     mSuccess = aResult;
     131           0 :   }
     132             : 
     133             :   NS_IMETHOD
     134           0 :   Run() override
     135             :   {
     136           0 :     AssertIsOnMainThread();
     137           0 :     mJob->ContinueUpdateAfterScriptEval(mSuccess);
     138           0 :     mJob = nullptr;
     139           0 :     return NS_OK;
     140             :   }
     141             : };
     142             : 
     143           0 : class ServiceWorkerUpdateJob::ContinueInstallRunnable final : public LifeCycleEventCallback
     144             : {
     145             :   nsMainThreadPtrHandle<ServiceWorkerUpdateJob> mJob;
     146             :   bool mSuccess;
     147             : 
     148             : public:
     149           0 :   explicit ContinueInstallRunnable(const nsMainThreadPtrHandle<ServiceWorkerUpdateJob>& aJob)
     150           0 :     : mJob(aJob)
     151           0 :     , mSuccess(false)
     152             :   {
     153           0 :     AssertIsOnMainThread();
     154           0 :   }
     155             : 
     156             :   void
     157           0 :   SetResult(bool aResult) override
     158             :   {
     159           0 :     mSuccess = aResult;
     160           0 :   }
     161             : 
     162             :   NS_IMETHOD
     163           0 :   Run() override
     164             :   {
     165           0 :     AssertIsOnMainThread();
     166           0 :     mJob->ContinueAfterInstallEvent(mSuccess);
     167           0 :     mJob = nullptr;
     168           0 :     return NS_OK;
     169             :   }
     170             : };
     171             : 
     172           0 : ServiceWorkerUpdateJob::ServiceWorkerUpdateJob(nsIPrincipal* aPrincipal,
     173             :                                                const nsACString& aScope,
     174             :                                                const nsACString& aScriptSpec,
     175             :                                                nsILoadGroup* aLoadGroup,
     176           0 :                                                nsLoadFlags aLoadFlags)
     177             :   : ServiceWorkerJob(Type::Update, aPrincipal, aScope, aScriptSpec)
     178             :   , mLoadGroup(aLoadGroup)
     179           0 :   , mLoadFlags(aLoadFlags)
     180             : {
     181           0 : }
     182             : 
     183             : already_AddRefed<ServiceWorkerRegistrationInfo>
     184           0 : ServiceWorkerUpdateJob::GetRegistration() const
     185             : {
     186           0 :   AssertIsOnMainThread();
     187           0 :   RefPtr<ServiceWorkerRegistrationInfo> ref = mRegistration;
     188           0 :   return ref.forget();
     189             : }
     190             : 
     191           0 : ServiceWorkerUpdateJob::ServiceWorkerUpdateJob(Type aType,
     192             :                                                nsIPrincipal* aPrincipal,
     193             :                                                const nsACString& aScope,
     194             :                                                const nsACString& aScriptSpec,
     195             :                                                nsILoadGroup* aLoadGroup,
     196           0 :                                                nsLoadFlags aLoadFlags)
     197             :   : ServiceWorkerJob(aType, aPrincipal, aScope, aScriptSpec)
     198             :   , mLoadGroup(aLoadGroup)
     199           0 :   , mLoadFlags(aLoadFlags)
     200             : {
     201           0 : }
     202             : 
     203           0 : ServiceWorkerUpdateJob::~ServiceWorkerUpdateJob()
     204             : {
     205           0 : }
     206             : 
     207             : void
     208           0 : ServiceWorkerUpdateJob::FailUpdateJob(ErrorResult& aRv)
     209             : {
     210           0 :   AssertIsOnMainThread();
     211           0 :   MOZ_ASSERT(aRv.Failed());
     212             : 
     213             :   // Cleanup after a failed installation.  This essentially implements
     214             :   // step 12 of the Install algorithm.
     215             :   //
     216             :   //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm
     217             :   //
     218             :   // The spec currently only runs this after an install event fails,
     219             :   // but we must handle many more internal errors.  So we check for
     220             :   // cleanup on every non-successful exit.
     221           0 :   if (mRegistration) {
     222           0 :     mRegistration->ClearEvaluating();
     223           0 :     mRegistration->ClearInstalling();
     224             : 
     225           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     226           0 :     if (swm) {
     227           0 :       swm->MaybeRemoveRegistration(mRegistration);
     228             :     }
     229             :   }
     230             : 
     231           0 :   mRegistration = nullptr;
     232             : 
     233           0 :   Finish(aRv);
     234           0 : }
     235             : 
     236             : void
     237           0 : ServiceWorkerUpdateJob::FailUpdateJob(nsresult aRv)
     238             : {
     239           0 :   ErrorResult rv(aRv);
     240           0 :   FailUpdateJob(rv);
     241           0 : }
     242             : 
     243             : void
     244           0 : ServiceWorkerUpdateJob::AsyncExecute()
     245             : {
     246           0 :   AssertIsOnMainThread();
     247           0 :   MOZ_ASSERT(GetType() == Type::Update);
     248             : 
     249           0 :   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     250           0 :   if (Canceled() || !swm) {
     251           0 :     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     252           0 :     return;
     253             :   }
     254             : 
     255             :   // Begin step 1 of the Update algorithm.
     256             :   //
     257             :   //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#update-algorithm
     258             : 
     259             :   RefPtr<ServiceWorkerRegistrationInfo> registration =
     260           0 :     swm->GetRegistration(mPrincipal, mScope);
     261             : 
     262           0 :   if (!registration || registration->mPendingUninstall) {
     263           0 :     ErrorResult rv;
     264           0 :     rv.ThrowTypeError<MSG_SW_UPDATE_BAD_REGISTRATION>(NS_ConvertUTF8toUTF16(mScope),
     265           0 :                                                       NS_LITERAL_STRING("uninstalled"));
     266           0 :     FailUpdateJob(rv);
     267           0 :     return;
     268             :   }
     269             : 
     270             :   // If a Register job with a new script executed ahead of us in the job queue,
     271             :   // then our update for the old script no longer makes sense.  Simply abort
     272             :   // in this case.
     273           0 :   RefPtr<ServiceWorkerInfo> newest = registration->Newest();
     274           0 :   if (newest && !mScriptSpec.Equals(newest->ScriptSpec())) {
     275           0 :     ErrorResult rv;
     276           0 :     rv.ThrowTypeError<MSG_SW_UPDATE_BAD_REGISTRATION>(NS_ConvertUTF8toUTF16(mScope),
     277           0 :                                                       NS_LITERAL_STRING("changed"));
     278           0 :     FailUpdateJob(rv);
     279           0 :     return;
     280             :   }
     281             : 
     282           0 :   SetRegistration(registration);
     283           0 :   Update();
     284             : }
     285             : 
     286             : void
     287           0 : ServiceWorkerUpdateJob::SetRegistration(ServiceWorkerRegistrationInfo* aRegistration)
     288             : {
     289           0 :   AssertIsOnMainThread();
     290             : 
     291           0 :   MOZ_ASSERT(!mRegistration);
     292           0 :   MOZ_ASSERT(aRegistration);
     293           0 :   mRegistration = aRegistration;
     294           0 : }
     295             : 
     296             : void
     297           0 : ServiceWorkerUpdateJob::Update()
     298             : {
     299           0 :   AssertIsOnMainThread();
     300           0 :   MOZ_ASSERT(!Canceled());
     301             : 
     302             :   // SetRegistration() must be called before Update().
     303           0 :   MOZ_ASSERT(mRegistration);
     304           0 :   MOZ_ASSERT(!mRegistration->GetInstalling());
     305             : 
     306             :   // Begin the script download and comparison steps starting at step 5
     307             :   // of the Update algorithm.
     308             : 
     309           0 :   RefPtr<ServiceWorkerInfo> workerInfo = mRegistration->Newest();
     310           0 :   nsAutoString cacheName;
     311             : 
     312             :   // If the script has not changed, we need to perform a byte-for-byte
     313             :   // comparison.
     314           0 :   if (workerInfo && workerInfo->ScriptSpec().Equals(mScriptSpec)) {
     315           0 :     cacheName = workerInfo->CacheName();
     316             :   }
     317             : 
     318           0 :   RefPtr<CompareCallback> callback = new CompareCallback(this);
     319             : 
     320             :   nsresult rv =
     321           0 :     serviceWorkerScriptCache::Compare(mRegistration, mPrincipal, cacheName,
     322           0 :                                       NS_ConvertUTF8toUTF16(mScriptSpec),
     323           0 :                                       callback, mLoadGroup);
     324           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     325           0 :     FailUpdateJob(rv);
     326           0 :     return;
     327             :   }
     328             : }
     329             : 
     330             : nsLoadFlags
     331           0 : ServiceWorkerUpdateJob::GetLoadFlags() const
     332             : {
     333           0 :   return mLoadFlags;
     334             : }
     335             : 
     336             : void
     337           0 : ServiceWorkerUpdateJob::ComparisonResult(nsresult aStatus,
     338             :                                          bool aInCacheAndEqual,
     339             :                                          const nsAString& aNewCacheName,
     340             :                                          const nsACString& aMaxScope,
     341             :                                          nsLoadFlags aLoadFlags)
     342             : {
     343           0 :   AssertIsOnMainThread();
     344             : 
     345           0 :   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     346           0 :   if (NS_WARN_IF(Canceled() || !swm)) {
     347           0 :     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     348           0 :     return;
     349             :   }
     350             : 
     351             :   // Handle failure of the download or comparison.  This is part of Update
     352             :   // step 5 as "If the algorithm asynchronously completes with null, then:".
     353           0 :   if (NS_WARN_IF(NS_FAILED(aStatus))) {
     354           0 :     FailUpdateJob(aStatus);
     355           0 :     return;
     356             :   }
     357             : 
     358             :   // The spec validates the response before performing the byte-for-byte check.
     359             :   // Here we perform the comparison in another module and then validate the
     360             :   // script URL and scope.  Make sure to do this validation before accepting
     361             :   // an byte-for-byte match since the service-worker-allowed header might have
     362             :   // changed since the last time it was installed.
     363             : 
     364             :   // This is step 2 the "validate response" section of Update algorithm step 5.
     365             :   // Step 1 is performed in the serviceWorkerScriptCache code.
     366             : 
     367           0 :   nsCOMPtr<nsIURI> scriptURI;
     368           0 :   nsresult rv = NS_NewURI(getter_AddRefs(scriptURI), mScriptSpec);
     369           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     370           0 :     FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
     371           0 :     return;
     372             :   }
     373             : 
     374           0 :   nsCOMPtr<nsIURI> maxScopeURI;
     375           0 :   if (!aMaxScope.IsEmpty()) {
     376           0 :     rv = NS_NewURI(getter_AddRefs(maxScopeURI), aMaxScope,
     377           0 :                    nullptr, scriptURI);
     378           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     379           0 :       FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
     380           0 :       return;
     381             :     }
     382             :   }
     383             : 
     384           0 :   mLoadFlags = aLoadFlags;
     385             : 
     386           0 :   nsAutoCString defaultAllowedPrefix;
     387           0 :   rv = GetRequiredScopeStringPrefix(scriptURI, defaultAllowedPrefix,
     388           0 :                                     eUseDirectory);
     389           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     390           0 :     FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
     391           0 :     return;
     392             :   }
     393             : 
     394           0 :   nsAutoCString maxPrefix(defaultAllowedPrefix);
     395           0 :   if (maxScopeURI) {
     396           0 :     rv = GetRequiredScopeStringPrefix(maxScopeURI, maxPrefix, eUsePath);
     397           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     398           0 :       FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
     399           0 :       return;
     400             :     }
     401             :   }
     402             : 
     403           0 :   if (!StringBeginsWith(mRegistration->mScope, maxPrefix)) {
     404           0 :     nsXPIDLString message;
     405           0 :     NS_ConvertUTF8toUTF16 reportScope(mRegistration->mScope);
     406           0 :     NS_ConvertUTF8toUTF16 reportMaxPrefix(maxPrefix);
     407           0 :     const char16_t* params[] = { reportScope.get(), reportMaxPrefix.get() };
     408             : 
     409             :     rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     410             :                                                "ServiceWorkerScopePathMismatch",
     411           0 :                                                params, message);
     412           0 :     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to format localized string");
     413           0 :     swm->ReportToAllClients(mScope,
     414             :                             message,
     415             :                             EmptyString(),
     416             :                             EmptyString(), 0, 0,
     417           0 :                             nsIScriptError::errorFlag);
     418           0 :     FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
     419           0 :     return;
     420             :   }
     421             : 
     422             :   // The response has been validated, so now we can consider if its a
     423             :   // byte-for-byte match.  This is step 6 of the Update algorithm.
     424           0 :   if (aInCacheAndEqual) {
     425           0 :     Finish(NS_OK);
     426           0 :     return;
     427             :   }
     428             : 
     429           0 :   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1);
     430             : 
     431             :   // Begin step 7 of the Update algorithm to evaluate the new script.
     432             : 
     433             :   RefPtr<ServiceWorkerInfo> sw =
     434           0 :     new ServiceWorkerInfo(mRegistration->mPrincipal,
     435           0 :                           mRegistration->mScope,
     436             :                           mScriptSpec,
     437             :                           aNewCacheName,
     438           0 :                           mLoadFlags);
     439             : 
     440           0 :   mRegistration->SetEvaluating(sw);
     441             : 
     442             :   nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
     443             :       new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(
     444           0 :         "ServiceWorkerUpdateJob", this));
     445           0 :   RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle);
     446             : 
     447           0 :   ServiceWorkerPrivate* workerPrivate = sw->WorkerPrivate();
     448           0 :   MOZ_ASSERT(workerPrivate);
     449           0 :   rv = workerPrivate->CheckScriptEvaluation(callback);
     450             : 
     451           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     452           0 :     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     453           0 :     return;
     454             :   }
     455             : }
     456             : 
     457             : void
     458           0 : ServiceWorkerUpdateJob::ContinueUpdateAfterScriptEval(bool aScriptEvaluationResult)
     459             : {
     460           0 :   AssertIsOnMainThread();
     461             : 
     462           0 :   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     463           0 :   if (Canceled() || !swm) {
     464           0 :     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     465           0 :     return;
     466             :   }
     467             : 
     468             :   // Step 7.5 of the Update algorithm verifying that the script evaluated
     469             :   // successfully.
     470             : 
     471           0 :   if (NS_WARN_IF(!aScriptEvaluationResult)) {
     472           0 :     ErrorResult error;
     473             : 
     474           0 :     NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
     475           0 :     NS_ConvertUTF8toUTF16 scope(mRegistration->mScope);
     476           0 :     error.ThrowTypeError<MSG_SW_SCRIPT_THREW>(scriptSpec, scope);
     477           0 :     FailUpdateJob(error);
     478           0 :     return;
     479             :   }
     480             : 
     481           0 :   Install(swm);
     482             : }
     483             : 
     484             : void
     485           0 : ServiceWorkerUpdateJob::Install(ServiceWorkerManager* aSWM)
     486             : {
     487           0 :   AssertIsOnMainThread();
     488           0 :   MOZ_DIAGNOSTIC_ASSERT(!Canceled());
     489           0 :   MOZ_DIAGNOSTIC_ASSERT(aSWM);
     490             : 
     491           0 :   MOZ_ASSERT(!mRegistration->GetInstalling());
     492             : 
     493             :   // Begin step 2 of the Install algorithm.
     494             :   //
     495             :   //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm
     496             : 
     497           0 :   mRegistration->TransitionEvaluatingToInstalling();
     498             : 
     499             :   // Step 6 of the Install algorithm resolving the job promise.
     500           0 :   InvokeResultCallbacks(NS_OK);
     501             : 
     502             :   // The job promise cannot be rejected after this point, but the job can
     503             :   // still fail; e.g. if the install event handler throws, etc.
     504             : 
     505             :   // fire the updatefound event
     506             :   nsCOMPtr<nsIRunnable> upr =
     507           0 :     NewRunnableMethod<RefPtr<ServiceWorkerRegistrationInfo>>(
     508             :       "dom::workers::ServiceWorkerManager::"
     509             :       "FireUpdateFoundOnServiceWorkerRegistrations",
     510             :       aSWM,
     511             :       &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations,
     512           0 :       mRegistration);
     513           0 :   NS_DispatchToMainThread(upr);
     514             : 
     515             :   // Call ContinueAfterInstallEvent(false) on main thread if the SW
     516             :   // script fails to load.
     517           0 :   nsCOMPtr<nsIRunnable> failRunnable = NewRunnableMethod<bool>(
     518             :     "dom::workers::ServiceWorkerUpdateJob::ContinueAfterInstallEvent",
     519             :     this,
     520             :     &ServiceWorkerUpdateJob::ContinueAfterInstallEvent,
     521           0 :     false);
     522             : 
     523             :   nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
     524             :     new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(
     525           0 :       "ServiceWorkerUpdateJob", this));
     526           0 :   RefPtr<LifeCycleEventCallback> callback = new ContinueInstallRunnable(handle);
     527             : 
     528             :   // Send the install event to the worker thread
     529             :   ServiceWorkerPrivate* workerPrivate =
     530           0 :     mRegistration->GetInstalling()->WorkerPrivate();
     531           0 :   nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"),
     532           0 :                                                   callback, failRunnable);
     533           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     534           0 :     ContinueAfterInstallEvent(false /* aSuccess */);
     535             :   }
     536           0 : }
     537             : 
     538             : void
     539           0 : ServiceWorkerUpdateJob::ContinueAfterInstallEvent(bool aInstallEventSuccess)
     540             : {
     541           0 :   if (Canceled()) {
     542           0 :     return FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     543             :   }
     544             : 
     545             :   // If we haven't been canceled we should have a registration.  There appears
     546             :   // to be a path where it gets cleared before we call into here.  Assert
     547             :   // to try to catch this condition, but don't crash in release.
     548           0 :   MOZ_DIAGNOSTIC_ASSERT(mRegistration);
     549           0 :   if (!mRegistration) {
     550           0 :     return FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     551             :   }
     552             : 
     553             :   // Continue executing the Install algorithm at step 12.
     554             : 
     555             :   // "If installFailed is true"
     556           0 :   if (NS_WARN_IF(!aInstallEventSuccess)) {
     557             :     // The installing worker is cleaned up by FailUpdateJob().
     558           0 :     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     559           0 :     return;
     560             :   }
     561             : 
     562           0 :   MOZ_DIAGNOSTIC_ASSERT(mRegistration->GetInstalling());
     563           0 :   mRegistration->TransitionInstallingToWaiting();
     564             : 
     565           0 :   Finish(NS_OK);
     566             : 
     567             :   // Step 20 calls for explicitly waiting for queued event tasks to fire.  Instead,
     568             :   // we simply queue a runnable to execute Activate.  This ensures the events are
     569             :   // flushed from the queue before proceeding.
     570             : 
     571             :   // Step 22 of the Install algorithm.  Activate is executed after the completion
     572             :   // of this job.  The controlling client and skipWaiting checks are performed
     573             :   // in TryToActivate().
     574           0 :   mRegistration->TryToActivateAsync();
     575             : }
     576             : 
     577             : } // namespace workers
     578             : } // namespace dom
     579             : } // namespace mozilla

Generated by: LCOV version 1.13