LCOV - code coverage report
Current view: top level - dom/workers - ServiceWorkerRegistration.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 10 562 1.8 %
Date: 2017-07-14 16:53:18 Functions: 2 122 1.6 %
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 "ServiceWorkerRegistration.h"
       8             : 
       9             : #include "ipc/ErrorIPCUtils.h"
      10             : #include "mozilla/dom/Notification.h"
      11             : #include "mozilla/dom/Promise.h"
      12             : #include "mozilla/dom/PromiseWorkerProxy.h"
      13             : #include "mozilla/dom/PushManagerBinding.h"
      14             : #include "mozilla/dom/PushManager.h"
      15             : #include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
      16             : #include "mozilla/Preferences.h"
      17             : #include "mozilla/Services.h"
      18             : #include "mozilla/Unused.h"
      19             : #include "nsCycleCollectionParticipant.h"
      20             : #include "nsNetUtil.h"
      21             : #include "nsServiceManagerUtils.h"
      22             : #include "ServiceWorker.h"
      23             : #include "ServiceWorkerManager.h"
      24             : 
      25             : #include "nsIDocument.h"
      26             : #include "nsIServiceWorkerManager.h"
      27             : #include "nsISupportsPrimitives.h"
      28             : #include "nsPIDOMWindow.h"
      29             : #include "nsContentUtils.h"
      30             : 
      31             : #include "WorkerPrivate.h"
      32             : #include "Workers.h"
      33             : #include "WorkerScope.h"
      34             : 
      35             : using namespace mozilla::dom::workers;
      36             : 
      37             : namespace mozilla {
      38             : namespace dom {
      39             : 
      40             : /* static */ bool
      41           1 : ServiceWorkerRegistration::Visible(JSContext* aCx, JSObject* aObj)
      42             : {
      43           1 :   if (NS_IsMainThread()) {
      44           0 :     return Preferences::GetBool("dom.serviceWorkers.enabled", false);
      45             :   }
      46             : 
      47             :   // Otherwise check the pref via the work private helper
      48           1 :   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
      49           1 :   if (!workerPrivate) {
      50           0 :     return false;
      51             :   }
      52             : 
      53           1 :   return workerPrivate->ServiceWorkersEnabled();
      54             : }
      55             : 
      56             : /* static */ bool
      57           1 : ServiceWorkerRegistration::NotificationAPIVisible(JSContext* aCx, JSObject* aObj)
      58             : {
      59           1 :   if (NS_IsMainThread()) {
      60           0 :     return Preferences::GetBool("dom.webnotifications.serviceworker.enabled", false);
      61             :   }
      62             : 
      63             :   // Otherwise check the pref via the work private helper
      64           1 :   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
      65           1 :   if (!workerPrivate) {
      66           0 :     return false;
      67             :   }
      68             : 
      69           1 :   return workerPrivate->DOMServiceWorkerNotificationEnabled();
      70             : }
      71             : 
      72             : ////////////////////////////////////////////////////
      73             : // Main Thread implementation
      74             : 
      75             : class ServiceWorkerRegistrationMainThread final : public ServiceWorkerRegistration,
      76             :                                                   public ServiceWorkerRegistrationListener
      77             : {
      78             :   friend nsPIDOMWindowInner;
      79             : public:
      80             :   NS_DECL_ISUPPORTS_INHERITED
      81           0 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerRegistrationMainThread,
      82             :                                            ServiceWorkerRegistration)
      83             : 
      84             :   ServiceWorkerRegistrationMainThread(nsPIDOMWindowInner* aWindow,
      85             :                                       const nsAString& aScope);
      86             : 
      87             :   already_AddRefed<Promise>
      88             :   Update(ErrorResult& aRv) override;
      89             : 
      90             :   already_AddRefed<Promise>
      91             :   Unregister(ErrorResult& aRv) override;
      92             : 
      93             :   // Partial interface from Notification API.
      94             :   already_AddRefed<Promise>
      95             :   ShowNotification(JSContext* aCx,
      96             :                    const nsAString& aTitle,
      97             :                    const NotificationOptions& aOptions,
      98             :                    ErrorResult& aRv) override;
      99             : 
     100             :   already_AddRefed<Promise>
     101             :   GetNotifications(const GetNotificationOptions& aOptions,
     102             :                    ErrorResult& aRv) override;
     103             : 
     104             :   already_AddRefed<ServiceWorker>
     105             :   GetInstalling() override;
     106             : 
     107             :   already_AddRefed<ServiceWorker>
     108             :   GetWaiting() override;
     109             : 
     110             :   already_AddRefed<ServiceWorker>
     111             :   GetActive() override;
     112             : 
     113             :   already_AddRefed<PushManager>
     114             :   GetPushManager(JSContext* aCx, ErrorResult& aRv) override;
     115             : 
     116             :   // DOMEventTargethelper
     117           0 :   void DisconnectFromOwner() override
     118             :   {
     119           0 :     StopListeningForEvents();
     120           0 :     ServiceWorkerRegistration::DisconnectFromOwner();
     121           0 :   }
     122             : 
     123             :   // ServiceWorkerRegistrationListener
     124             :   void
     125             :   UpdateFound() override;
     126             : 
     127             :   void
     128             :   InvalidateWorkers(WhichServiceWorker aWhichOnes) override;
     129             : 
     130             :   void
     131             :   TransitionWorker(WhichServiceWorker aWhichOne) override;
     132             : 
     133             :   void
     134             :   RegistrationRemoved() override;
     135             : 
     136             :   void
     137           0 :   GetScope(nsAString& aScope) const override
     138             :   {
     139           0 :     aScope = mScope;
     140           0 :   }
     141             : 
     142             : private:
     143             :   ~ServiceWorkerRegistrationMainThread();
     144             : 
     145             :   already_AddRefed<ServiceWorker>
     146             :   GetWorkerReference(WhichServiceWorker aWhichOne);
     147             : 
     148             :   void
     149             :   StartListeningForEvents();
     150             : 
     151             :   void
     152             :   StopListeningForEvents();
     153             : 
     154             :   bool mListeningForEvents;
     155             : 
     156             :   // The following properties are cached here to ensure JS equality is satisfied
     157             :   // instead of acquiring a new worker instance from the ServiceWorkerManager
     158             :   // for every access. A null value is considered a cache miss.
     159             :   // These three may change to a new worker at any time.
     160             :   RefPtr<ServiceWorker> mInstallingWorker;
     161             :   RefPtr<ServiceWorker> mWaitingWorker;
     162             :   RefPtr<ServiceWorker> mActiveWorker;
     163             : 
     164             :   RefPtr<PushManager> mPushManager;
     165             : };
     166             : 
     167           0 : NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistrationMainThread, ServiceWorkerRegistration)
     168           0 : NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistrationMainThread, ServiceWorkerRegistration)
     169             : 
     170           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistrationMainThread)
     171           0 : NS_INTERFACE_MAP_END_INHERITING(ServiceWorkerRegistration)
     172             : 
     173           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistrationMainThread,
     174             :                                    ServiceWorkerRegistration,
     175             :                                    mPushManager,
     176             :                                    mInstallingWorker, mWaitingWorker, mActiveWorker);
     177             : 
     178           0 : ServiceWorkerRegistrationMainThread::ServiceWorkerRegistrationMainThread(nsPIDOMWindowInner* aWindow,
     179           0 :                                                                          const nsAString& aScope)
     180             :   : ServiceWorkerRegistration(aWindow, aScope)
     181           0 :   , mListeningForEvents(false)
     182             : {
     183           0 :   AssertIsOnMainThread();
     184           0 :   MOZ_ASSERT(aWindow);
     185           0 :   MOZ_ASSERT(aWindow->IsInnerWindow());
     186           0 :   StartListeningForEvents();
     187           0 : }
     188             : 
     189           0 : ServiceWorkerRegistrationMainThread::~ServiceWorkerRegistrationMainThread()
     190             : {
     191           0 :   StopListeningForEvents();
     192           0 :   MOZ_ASSERT(!mListeningForEvents);
     193           0 : }
     194             : 
     195             : 
     196             : already_AddRefed<ServiceWorker>
     197           0 : ServiceWorkerRegistrationMainThread::GetWorkerReference(WhichServiceWorker aWhichOne)
     198             : {
     199           0 :   nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
     200           0 :   if (!window) {
     201           0 :     return nullptr;
     202             :   }
     203             : 
     204             :   nsresult rv;
     205             :   nsCOMPtr<nsIServiceWorkerManager> swm =
     206           0 :     do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
     207           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     208           0 :     return nullptr;
     209             :   }
     210             : 
     211           0 :   nsCOMPtr<nsISupports> serviceWorker;
     212           0 :   switch(aWhichOne) {
     213             :     case WhichServiceWorker::INSTALLING_WORKER:
     214           0 :       rv = swm->GetInstalling(window, mScope, getter_AddRefs(serviceWorker));
     215           0 :       break;
     216             :     case WhichServiceWorker::WAITING_WORKER:
     217           0 :       rv = swm->GetWaiting(window, mScope, getter_AddRefs(serviceWorker));
     218           0 :       break;
     219             :     case WhichServiceWorker::ACTIVE_WORKER:
     220           0 :       rv = swm->GetActive(window, mScope, getter_AddRefs(serviceWorker));
     221           0 :       break;
     222             :     default:
     223           0 :       MOZ_CRASH("Invalid enum value");
     224             :   }
     225             : 
     226           0 :   NS_WARNING_ASSERTION(
     227             :     NS_SUCCEEDED(rv) || rv == NS_ERROR_DOM_NOT_FOUND_ERR,
     228             :     "Unexpected error getting service worker instance from "
     229             :     "ServiceWorkerManager");
     230           0 :   if (NS_FAILED(rv)) {
     231           0 :     return nullptr;
     232             :   }
     233             : 
     234             :   RefPtr<ServiceWorker> ref =
     235           0 :     static_cast<ServiceWorker*>(serviceWorker.get());
     236           0 :   return ref.forget();
     237             : }
     238             : 
     239             : // XXXnsm, maybe this can be optimized to only add when a event handler is
     240             : // registered.
     241             : void
     242           0 : ServiceWorkerRegistrationMainThread::StartListeningForEvents()
     243             : {
     244           0 :   AssertIsOnMainThread();
     245           0 :   MOZ_ASSERT(!mListeningForEvents);
     246           0 :   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     247           0 :   if (swm) {
     248           0 :     swm->AddRegistrationEventListener(mScope, this);
     249           0 :     mListeningForEvents = true;
     250             :   }
     251           0 : }
     252             : 
     253             : void
     254           0 : ServiceWorkerRegistrationMainThread::StopListeningForEvents()
     255             : {
     256           0 :   AssertIsOnMainThread();
     257           0 :   if (!mListeningForEvents) {
     258           0 :     return;
     259             :   }
     260             : 
     261           0 :   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     262           0 :   if (swm) {
     263           0 :     swm->RemoveRegistrationEventListener(mScope, this);
     264             :   }
     265           0 :   mListeningForEvents = false;
     266             : }
     267             : 
     268             : already_AddRefed<ServiceWorker>
     269           0 : ServiceWorkerRegistrationMainThread::GetInstalling()
     270             : {
     271           0 :   AssertIsOnMainThread();
     272           0 :   if (!mInstallingWorker) {
     273           0 :     mInstallingWorker = GetWorkerReference(WhichServiceWorker::INSTALLING_WORKER);
     274             :   }
     275             : 
     276           0 :   RefPtr<ServiceWorker> ret = mInstallingWorker;
     277           0 :   return ret.forget();
     278             : }
     279             : 
     280             : already_AddRefed<ServiceWorker>
     281           0 : ServiceWorkerRegistrationMainThread::GetWaiting()
     282             : {
     283           0 :   AssertIsOnMainThread();
     284           0 :   if (!mWaitingWorker) {
     285           0 :     mWaitingWorker = GetWorkerReference(WhichServiceWorker::WAITING_WORKER);
     286             :   }
     287             : 
     288           0 :   RefPtr<ServiceWorker> ret = mWaitingWorker;
     289           0 :   return ret.forget();
     290             : }
     291             : 
     292             : already_AddRefed<ServiceWorker>
     293           0 : ServiceWorkerRegistrationMainThread::GetActive()
     294             : {
     295           0 :   AssertIsOnMainThread();
     296           0 :   if (!mActiveWorker) {
     297           0 :     mActiveWorker = GetWorkerReference(WhichServiceWorker::ACTIVE_WORKER);
     298             :   }
     299             : 
     300           0 :   RefPtr<ServiceWorker> ret = mActiveWorker;
     301           0 :   return ret.forget();
     302             : }
     303             : 
     304             : void
     305           0 : ServiceWorkerRegistrationMainThread::UpdateFound()
     306             : {
     307           0 :   DispatchTrustedEvent(NS_LITERAL_STRING("updatefound"));
     308           0 : }
     309             : 
     310             : void
     311           0 : ServiceWorkerRegistrationMainThread::TransitionWorker(WhichServiceWorker aWhichOne)
     312             : {
     313           0 :   AssertIsOnMainThread();
     314             : 
     315             :   // We assert the worker's previous state because the 'statechange'
     316             :   // event is dispatched in a queued runnable.
     317           0 :   if (aWhichOne == WhichServiceWorker::INSTALLING_WORKER) {
     318           0 :     MOZ_ASSERT_IF(mInstallingWorker, mInstallingWorker->State() == ServiceWorkerState::Installing);
     319           0 :     mWaitingWorker = mInstallingWorker.forget();
     320           0 :   } else if (aWhichOne == WhichServiceWorker::WAITING_WORKER) {
     321           0 :     MOZ_ASSERT_IF(mWaitingWorker, mWaitingWorker->State() == ServiceWorkerState::Installed);
     322           0 :     mActiveWorker = mWaitingWorker.forget();
     323             :   } else {
     324           0 :     MOZ_ASSERT_UNREACHABLE("Invalid transition!");
     325             :   }
     326           0 : }
     327             : 
     328             : void
     329           0 : ServiceWorkerRegistrationMainThread::InvalidateWorkers(WhichServiceWorker aWhichOnes)
     330             : {
     331           0 :   AssertIsOnMainThread();
     332           0 :   if (aWhichOnes & WhichServiceWorker::INSTALLING_WORKER) {
     333           0 :     mInstallingWorker = nullptr;
     334             :   }
     335             : 
     336           0 :   if (aWhichOnes & WhichServiceWorker::WAITING_WORKER) {
     337           0 :     mWaitingWorker = nullptr;
     338             :   }
     339             : 
     340           0 :   if (aWhichOnes & WhichServiceWorker::ACTIVE_WORKER) {
     341           0 :     mActiveWorker = nullptr;
     342             :   }
     343             : 
     344           0 : }
     345             : 
     346             : void
     347           0 : ServiceWorkerRegistrationMainThread::RegistrationRemoved()
     348             : {
     349             :   // If the registration is being removed completely, remove it from the
     350             :   // window registration hash table so that a new registration would get a new
     351             :   // wrapper JS object.
     352           0 :   if (nsCOMPtr<nsPIDOMWindowInner> window = GetOwner()) {
     353           0 :     window->InvalidateServiceWorkerRegistration(mScope);
     354             :   }
     355           0 : }
     356             : 
     357             : namespace {
     358             : 
     359             : void
     360           0 : UpdateInternal(nsIPrincipal* aPrincipal,
     361             :                const nsAString& aScope,
     362             :                ServiceWorkerUpdateFinishCallback* aCallback)
     363             : {
     364           0 :   AssertIsOnMainThread();
     365           0 :   MOZ_ASSERT(aPrincipal);
     366           0 :   MOZ_ASSERT(aCallback);
     367             : 
     368           0 :   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     369           0 :   if (!swm) {
     370             :     // browser shutdown
     371           0 :     return;
     372             :   }
     373             : 
     374           0 :   swm->Update(aPrincipal, NS_ConvertUTF16toUTF8(aScope), aCallback);
     375             : }
     376             : 
     377             : class MainThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
     378             : {
     379             :   RefPtr<Promise> mPromise;
     380             : 
     381           0 :   ~MainThreadUpdateCallback()
     382           0 :   { }
     383             : 
     384             : public:
     385           0 :   explicit MainThreadUpdateCallback(Promise* aPromise)
     386           0 :     : mPromise(aPromise)
     387             :   {
     388           0 :     AssertIsOnMainThread();
     389           0 :   }
     390             : 
     391             :   void
     392           0 :   UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override
     393             :   {
     394           0 :     mPromise->MaybeResolveWithUndefined();
     395           0 :   }
     396             : 
     397             :   void
     398           0 :   UpdateFailed(ErrorResult& aStatus) override
     399             :   {
     400           0 :     mPromise->MaybeReject(aStatus);
     401           0 :   }
     402             : };
     403             : 
     404             : class UpdateResultRunnable final : public WorkerRunnable
     405             : {
     406             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     407             :   IPC::Message mSerializedErrorResult;
     408             : 
     409           0 :   ~UpdateResultRunnable()
     410           0 :   {}
     411             : 
     412             : public:
     413           0 :   UpdateResultRunnable(PromiseWorkerProxy* aPromiseProxy, ErrorResult& aStatus)
     414           0 :     : WorkerRunnable(aPromiseProxy->GetWorkerPrivate())
     415           0 :     , mPromiseProxy(aPromiseProxy)
     416             :   {
     417             :     // ErrorResult is not thread safe.  Serialize it for transfer across
     418             :     // threads.
     419           0 :     IPC::WriteParam(&mSerializedErrorResult, aStatus);
     420           0 :     aStatus.SuppressException();
     421           0 :   }
     422             : 
     423             :   bool
     424           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     425             :   {
     426             :     // Deserialize the ErrorResult now that we are back in the worker
     427             :     // thread.
     428           0 :     ErrorResult status;
     429           0 :     PickleIterator iter = PickleIterator(mSerializedErrorResult);
     430           0 :     Unused << IPC::ReadParam(&mSerializedErrorResult, &iter, &status);
     431             : 
     432           0 :     Promise* promise = mPromiseProxy->WorkerPromise();
     433           0 :     if (status.Failed()) {
     434           0 :       promise->MaybeReject(status);
     435             :     } else {
     436           0 :       promise->MaybeResolveWithUndefined();
     437             :     }
     438           0 :     status.SuppressException();
     439           0 :     mPromiseProxy->CleanUp();
     440           0 :     return true;
     441             :   }
     442             : };
     443             : 
     444             : class WorkerThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
     445             : {
     446             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     447             : 
     448           0 :   ~WorkerThreadUpdateCallback()
     449           0 :   {
     450           0 :   }
     451             : 
     452             : public:
     453           0 :   explicit WorkerThreadUpdateCallback(PromiseWorkerProxy* aPromiseProxy)
     454           0 :     : mPromiseProxy(aPromiseProxy)
     455             :   {
     456           0 :     AssertIsOnMainThread();
     457           0 :   }
     458             : 
     459             :   void
     460           0 :   UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override
     461             :   {
     462           0 :     ErrorResult rv(NS_OK);
     463           0 :     Finish(rv);
     464           0 :   }
     465             : 
     466             :   void
     467           0 :   UpdateFailed(ErrorResult& aStatus) override
     468             :   {
     469           0 :     Finish(aStatus);
     470           0 :   }
     471             : 
     472             :   void
     473           0 :   Finish(ErrorResult& aStatus)
     474             :   {
     475           0 :     if (!mPromiseProxy) {
     476           0 :       return;
     477             :     }
     478             : 
     479           0 :     RefPtr<PromiseWorkerProxy> proxy = mPromiseProxy.forget();
     480             : 
     481           0 :     MutexAutoLock lock(proxy->Lock());
     482           0 :     if (proxy->CleanedUp()) {
     483           0 :       return;
     484             :     }
     485             : 
     486             :     RefPtr<UpdateResultRunnable> r =
     487           0 :       new UpdateResultRunnable(proxy, aStatus);
     488           0 :     r->Dispatch();
     489             :   }
     490             : };
     491             : 
     492             : class UpdateRunnable final : public Runnable
     493             : {
     494             : public:
     495           0 :   UpdateRunnable(PromiseWorkerProxy* aPromiseProxy, const nsAString& aScope)
     496           0 :     : Runnable("dom::UpdateRunnable")
     497             :     , mPromiseProxy(aPromiseProxy)
     498           0 :     , mScope(aScope)
     499           0 :   {}
     500             : 
     501             :   NS_IMETHOD
     502           0 :   Run() override
     503             :   {
     504           0 :     AssertIsOnMainThread();
     505           0 :     ErrorResult result;
     506             : 
     507           0 :     nsCOMPtr<nsIPrincipal> principal;
     508             :     // UpdateInternal may try to reject the promise synchronously leading
     509             :     // to a deadlock.
     510             :     {
     511           0 :       MutexAutoLock lock(mPromiseProxy->Lock());
     512           0 :       if (mPromiseProxy->CleanedUp()) {
     513           0 :         return NS_OK;
     514             :       }
     515             : 
     516           0 :       principal = mPromiseProxy->GetWorkerPrivate()->GetPrincipal();
     517             :     }
     518           0 :     MOZ_ASSERT(principal);
     519             : 
     520             :     RefPtr<WorkerThreadUpdateCallback> cb =
     521           0 :       new WorkerThreadUpdateCallback(mPromiseProxy);
     522           0 :     UpdateInternal(principal, mScope, cb);
     523           0 :     return NS_OK;
     524             :   }
     525             : 
     526             : private:
     527           0 :   ~UpdateRunnable()
     528           0 :   {}
     529             : 
     530             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     531             :   const nsString mScope;
     532             : };
     533             : 
     534             : class UnregisterCallback final : public nsIServiceWorkerUnregisterCallback
     535             : {
     536             :   RefPtr<Promise> mPromise;
     537             : 
     538             : public:
     539             :   NS_DECL_ISUPPORTS
     540             : 
     541           0 :   explicit UnregisterCallback(Promise* aPromise)
     542           0 :     : mPromise(aPromise)
     543             :   {
     544           0 :     MOZ_ASSERT(mPromise);
     545           0 :   }
     546             : 
     547             :   NS_IMETHOD
     548           0 :   UnregisterSucceeded(bool aState) override
     549             :   {
     550           0 :     AssertIsOnMainThread();
     551           0 :     mPromise->MaybeResolve(aState);
     552           0 :     return NS_OK;
     553             :   }
     554             : 
     555             :   NS_IMETHOD
     556           0 :   UnregisterFailed() override
     557             :   {
     558           0 :     AssertIsOnMainThread();
     559             : 
     560           0 :     mPromise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     561           0 :     return NS_OK;
     562             :   }
     563             : 
     564             : private:
     565           0 :   ~UnregisterCallback()
     566           0 :   { }
     567             : };
     568             : 
     569           0 : NS_IMPL_ISUPPORTS(UnregisterCallback, nsIServiceWorkerUnregisterCallback)
     570             : 
     571           0 : class FulfillUnregisterPromiseRunnable final : public WorkerRunnable
     572             : {
     573             :   RefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
     574             :   Maybe<bool> mState;
     575             : public:
     576           0 :   FulfillUnregisterPromiseRunnable(PromiseWorkerProxy* aProxy,
     577             :                                    const Maybe<bool>& aState)
     578           0 :     : WorkerRunnable(aProxy->GetWorkerPrivate())
     579             :     , mPromiseWorkerProxy(aProxy)
     580           0 :     , mState(aState)
     581             :   {
     582           0 :     AssertIsOnMainThread();
     583           0 :     MOZ_ASSERT(mPromiseWorkerProxy);
     584           0 :   }
     585             : 
     586             :   bool
     587           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     588             :   {
     589           0 :     RefPtr<Promise> promise = mPromiseWorkerProxy->WorkerPromise();
     590           0 :     if (mState.isSome()) {
     591           0 :       promise->MaybeResolve(mState.value());
     592             :     } else {
     593           0 :       promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     594             :     }
     595             : 
     596           0 :     mPromiseWorkerProxy->CleanUp();
     597           0 :     return true;
     598             :   }
     599             : };
     600             : 
     601             : class WorkerUnregisterCallback final : public nsIServiceWorkerUnregisterCallback
     602             : {
     603             :   RefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
     604             : public:
     605             :   NS_DECL_ISUPPORTS
     606             : 
     607           0 :   explicit WorkerUnregisterCallback(PromiseWorkerProxy* aProxy)
     608           0 :     : mPromiseWorkerProxy(aProxy)
     609             :   {
     610           0 :     MOZ_ASSERT(aProxy);
     611           0 :   }
     612             : 
     613             :   NS_IMETHOD
     614           0 :   UnregisterSucceeded(bool aState) override
     615             :   {
     616           0 :     AssertIsOnMainThread();
     617           0 :     Finish(Some(aState));
     618           0 :     return NS_OK;
     619             :   }
     620             : 
     621             :   NS_IMETHOD
     622           0 :   UnregisterFailed() override
     623             :   {
     624           0 :     AssertIsOnMainThread();
     625           0 :     Finish(Nothing());
     626           0 :     return NS_OK;
     627             :   }
     628             : 
     629             : private:
     630           0 :   ~WorkerUnregisterCallback()
     631           0 :   {}
     632             : 
     633             :   void
     634           0 :   Finish(const Maybe<bool>& aState)
     635             :   {
     636           0 :     AssertIsOnMainThread();
     637           0 :     if (!mPromiseWorkerProxy) {
     638           0 :       return;
     639             :     }
     640             : 
     641           0 :     RefPtr<PromiseWorkerProxy> proxy = mPromiseWorkerProxy.forget();
     642           0 :     MutexAutoLock lock(proxy->Lock());
     643           0 :     if (proxy->CleanedUp()) {
     644           0 :       return;
     645             :     }
     646             : 
     647             :     RefPtr<WorkerRunnable> r =
     648           0 :       new FulfillUnregisterPromiseRunnable(proxy, aState);
     649             : 
     650           0 :     r->Dispatch();
     651             :   }
     652             : };
     653             : 
     654           0 : NS_IMPL_ISUPPORTS(WorkerUnregisterCallback, nsIServiceWorkerUnregisterCallback);
     655             : 
     656             : /*
     657             :  * If the worker goes away, we still continue to unregister, but we don't try to
     658             :  * resolve the worker Promise (which doesn't exist by that point).
     659             :  */
     660           0 : class StartUnregisterRunnable final : public Runnable
     661             : {
     662             :   RefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
     663             :   const nsString mScope;
     664             : 
     665             : public:
     666           0 :   StartUnregisterRunnable(PromiseWorkerProxy* aProxy, const nsAString& aScope)
     667           0 :     : Runnable("dom::StartUnregisterRunnable")
     668             :     , mPromiseWorkerProxy(aProxy)
     669           0 :     , mScope(aScope)
     670             :   {
     671           0 :     MOZ_ASSERT(aProxy);
     672           0 :   }
     673             : 
     674             :   NS_IMETHOD
     675           0 :   Run() override
     676             :   {
     677           0 :     AssertIsOnMainThread();
     678             : 
     679             :     // XXXnsm: There is a rare chance of this failing if the worker gets
     680             :     // destroyed. In that case, unregister() called from a SW is no longer
     681             :     // guaranteed to run. We should fix this by having a main thread proxy
     682             :     // maintain a strongref to ServiceWorkerRegistrationInfo and use its
     683             :     // principal. Can that be trusted?
     684           0 :     nsCOMPtr<nsIPrincipal> principal;
     685             :     {
     686           0 :       MutexAutoLock lock(mPromiseWorkerProxy->Lock());
     687           0 :       if (mPromiseWorkerProxy->CleanedUp()) {
     688           0 :         return NS_OK;
     689             :       }
     690             : 
     691           0 :       WorkerPrivate* worker = mPromiseWorkerProxy->GetWorkerPrivate();
     692           0 :       MOZ_ASSERT(worker);
     693           0 :       principal = worker->GetPrincipal();
     694             :     }
     695           0 :     MOZ_ASSERT(principal);
     696             : 
     697             :     RefPtr<WorkerUnregisterCallback> cb =
     698           0 :       new WorkerUnregisterCallback(mPromiseWorkerProxy);
     699             :     nsCOMPtr<nsIServiceWorkerManager> swm =
     700           0 :       mozilla::services::GetServiceWorkerManager();
     701           0 :     nsresult rv = swm->Unregister(principal, cb, mScope);
     702           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     703           0 :       cb->UnregisterFailed();
     704             :     }
     705             : 
     706           0 :     return NS_OK;
     707             :   }
     708             : };
     709             : } // namespace
     710             : 
     711             : already_AddRefed<Promise>
     712           0 : ServiceWorkerRegistrationMainThread::Update(ErrorResult& aRv)
     713             : {
     714           0 :   AssertIsOnMainThread();
     715           0 :   nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(GetOwner());
     716           0 :   if (!go) {
     717           0 :     aRv.Throw(NS_ERROR_FAILURE);
     718           0 :     return nullptr;
     719             :   }
     720             : 
     721           0 :   RefPtr<Promise> promise = Promise::Create(go, aRv);
     722           0 :   if (NS_WARN_IF(aRv.Failed())) {
     723           0 :     return nullptr;
     724             :   }
     725             : 
     726           0 :   nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
     727           0 :   MOZ_ASSERT(doc);
     728             : 
     729             :   RefPtr<MainThreadUpdateCallback> cb =
     730           0 :     new MainThreadUpdateCallback(promise);
     731           0 :   UpdateInternal(doc->NodePrincipal(), mScope, cb);
     732             : 
     733           0 :   return promise.forget();
     734             : }
     735             : 
     736             : already_AddRefed<Promise>
     737           0 : ServiceWorkerRegistrationMainThread::Unregister(ErrorResult& aRv)
     738             : {
     739           0 :   AssertIsOnMainThread();
     740           0 :   nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(GetOwner());
     741           0 :   if (!go) {
     742           0 :     aRv.Throw(NS_ERROR_FAILURE);
     743           0 :     return nullptr;
     744             :   }
     745             : 
     746             :   // Although the spec says that the same-origin checks should also be done
     747             :   // asynchronously, we do them in sync because the Promise created by the
     748             :   // WebIDL infrastructure due to a returned error will be resolved
     749             :   // asynchronously. We aren't making any internal state changes in these
     750             :   // checks, so ordering of multiple calls is not affected.
     751           0 :   nsCOMPtr<nsIDocument> document = GetOwner()->GetExtantDoc();
     752           0 :   if (!document) {
     753           0 :     aRv.Throw(NS_ERROR_FAILURE);
     754           0 :     return nullptr;
     755             :   }
     756             : 
     757           0 :   nsCOMPtr<nsIURI> scopeURI;
     758           0 :   nsCOMPtr<nsIURI> baseURI = document->GetBaseURI();
     759             :   // "If the origin of scope is not client's origin..."
     760           0 :   nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), mScope, nullptr, baseURI);
     761           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     762           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     763           0 :     return nullptr;
     764             :   }
     765             : 
     766           0 :   nsCOMPtr<nsIPrincipal> documentPrincipal = document->NodePrincipal();
     767           0 :   rv = documentPrincipal->CheckMayLoad(scopeURI, true /* report */,
     768           0 :                                        false /* allowIfInheritsPrinciple */);
     769           0 :   if (NS_FAILED(rv)) {
     770           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     771           0 :     return nullptr;
     772             :   }
     773             : 
     774           0 :   nsAutoCString uriSpec;
     775           0 :   aRv = scopeURI->GetSpecIgnoringRef(uriSpec);
     776           0 :   if (NS_WARN_IF(aRv.Failed())) {
     777           0 :     return nullptr;
     778             :   }
     779             : 
     780             :   nsCOMPtr<nsIServiceWorkerManager> swm =
     781           0 :     mozilla::services::GetServiceWorkerManager();
     782             : 
     783           0 :   RefPtr<Promise> promise = Promise::Create(go, aRv);
     784           0 :   if (NS_WARN_IF(aRv.Failed())) {
     785           0 :     return nullptr;
     786             :   }
     787             : 
     788           0 :   RefPtr<UnregisterCallback> cb = new UnregisterCallback(promise);
     789             : 
     790           0 :   NS_ConvertUTF8toUTF16 scope(uriSpec);
     791           0 :   aRv = swm->Unregister(documentPrincipal, cb, scope);
     792           0 :   if (aRv.Failed()) {
     793           0 :     return nullptr;
     794             :   }
     795             : 
     796           0 :   return promise.forget();
     797             : }
     798             : 
     799             : // Notification API extension.
     800             : already_AddRefed<Promise>
     801           0 : ServiceWorkerRegistrationMainThread::ShowNotification(JSContext* aCx,
     802             :                                                       const nsAString& aTitle,
     803             :                                                       const NotificationOptions& aOptions,
     804             :                                                       ErrorResult& aRv)
     805             : {
     806           0 :   AssertIsOnMainThread();
     807           0 :   nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
     808           0 :   if (NS_WARN_IF(!window)) {
     809           0 :     aRv.Throw(NS_ERROR_FAILURE);
     810           0 :     return nullptr;
     811             :   }
     812             : 
     813           0 :   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
     814           0 :   if (NS_WARN_IF(!doc)) {
     815           0 :     aRv.Throw(NS_ERROR_FAILURE);
     816           0 :     return nullptr;
     817             :   }
     818             : 
     819           0 :   RefPtr<ServiceWorker> worker = GetActive();
     820           0 :   if (!worker) {
     821           0 :     aRv.ThrowTypeError<MSG_NO_ACTIVE_WORKER>(mScope);
     822           0 :     return nullptr;
     823             :   }
     824             : 
     825           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
     826             :   RefPtr<Promise> p =
     827           0 :     Notification::ShowPersistentNotification(aCx, global, mScope, aTitle,
     828           0 :                                              aOptions, aRv);
     829           0 :   if (NS_WARN_IF(aRv.Failed())) {
     830           0 :     return nullptr;
     831             :   }
     832             : 
     833           0 :   return p.forget();
     834             : }
     835             : 
     836             : already_AddRefed<Promise>
     837           0 : ServiceWorkerRegistrationMainThread::GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv)
     838             : {
     839           0 :   AssertIsOnMainThread();
     840           0 :   nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
     841           0 :   if (NS_WARN_IF(!window)) {
     842           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     843           0 :     return nullptr;
     844             :   }
     845           0 :   return Notification::Get(window, aOptions, mScope, aRv);
     846             : }
     847             : 
     848             : already_AddRefed<PushManager>
     849           0 : ServiceWorkerRegistrationMainThread::GetPushManager(JSContext* aCx,
     850             :                                                     ErrorResult& aRv)
     851             : {
     852           0 :   AssertIsOnMainThread();
     853             : 
     854           0 :   if (!mPushManager) {
     855           0 :     nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
     856             : 
     857           0 :     if (!globalObject) {
     858           0 :       aRv.Throw(NS_ERROR_FAILURE);
     859           0 :       return nullptr;
     860             :     }
     861             : 
     862           0 :     GlobalObject global(aCx, globalObject->GetGlobalJSObject());
     863           0 :     mPushManager = PushManager::Constructor(global, mScope, aRv);
     864           0 :     if (aRv.Failed()) {
     865           0 :       return nullptr;
     866             :     }
     867             :   }
     868             : 
     869           0 :   RefPtr<PushManager> ret = mPushManager;
     870           0 :   return ret.forget();
     871             : }
     872             : 
     873             : ////////////////////////////////////////////////////
     874             : // Worker Thread implementation
     875             : 
     876             : class ServiceWorkerRegistrationWorkerThread final : public ServiceWorkerRegistration
     877             :                                                   , public WorkerHolder
     878             : {
     879             : public:
     880             :   NS_DECL_ISUPPORTS_INHERITED
     881           0 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerRegistrationWorkerThread,
     882             :                                            ServiceWorkerRegistration)
     883             : 
     884             :   ServiceWorkerRegistrationWorkerThread(WorkerPrivate* aWorkerPrivate,
     885             :                                         const nsAString& aScope);
     886             : 
     887             :   already_AddRefed<Promise>
     888             :   Update(ErrorResult& aRv) override;
     889             : 
     890             :   already_AddRefed<Promise>
     891             :   Unregister(ErrorResult& aRv) override;
     892             : 
     893             :   // Partial interface from Notification API.
     894             :   already_AddRefed<Promise>
     895             :   ShowNotification(JSContext* aCx,
     896             :                    const nsAString& aTitle,
     897             :                    const NotificationOptions& aOptions,
     898             :                    ErrorResult& aRv) override;
     899             : 
     900             :   already_AddRefed<Promise>
     901             :   GetNotifications(const GetNotificationOptions& aOptions,
     902             :                    ErrorResult& aRv) override;
     903             : 
     904             :   already_AddRefed<ServiceWorker>
     905             :   GetInstalling() override;
     906             : 
     907             :   already_AddRefed<ServiceWorker>
     908             :   GetWaiting() override;
     909             : 
     910             :   already_AddRefed<ServiceWorker>
     911             :   GetActive() override;
     912             : 
     913             :   void
     914           0 :   GetScope(nsAString& aScope) const override
     915             :   {
     916           0 :     aScope = mScope;
     917           0 :   }
     918             : 
     919             :   bool
     920             :   Notify(Status aStatus) override;
     921             : 
     922             :   already_AddRefed<PushManager>
     923             :   GetPushManager(JSContext* aCx, ErrorResult& aRv) override;
     924             : 
     925             : private:
     926             :   ~ServiceWorkerRegistrationWorkerThread();
     927             : 
     928             :   void
     929             :   InitListener();
     930             : 
     931             :   void
     932             :   ReleaseListener();
     933             : 
     934             :   WorkerPrivate* mWorkerPrivate;
     935             :   RefPtr<WorkerListener> mListener;
     936             : 
     937             :   RefPtr<PushManager> mPushManager;
     938             : };
     939             : 
     940             : class WorkerListener final : public ServiceWorkerRegistrationListener
     941             : {
     942             :   // Accessed on the main thread.
     943             :   WorkerPrivate* mWorkerPrivate;
     944             :   nsString mScope;
     945             :   bool mListeningForEvents;
     946             : 
     947             :   // Accessed on the worker thread.
     948             :   ServiceWorkerRegistrationWorkerThread* mRegistration;
     949             : 
     950             : public:
     951           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerListener, override)
     952             : 
     953           0 :   WorkerListener(WorkerPrivate* aWorkerPrivate,
     954             :                  ServiceWorkerRegistrationWorkerThread* aReg)
     955           0 :     : mWorkerPrivate(aWorkerPrivate)
     956             :     , mListeningForEvents(false)
     957           0 :     , mRegistration(aReg)
     958             :   {
     959           0 :     MOZ_ASSERT(mWorkerPrivate);
     960           0 :     mWorkerPrivate->AssertIsOnWorkerThread();
     961           0 :     MOZ_ASSERT(mRegistration);
     962             :     // Copy scope so we can return it on the main thread.
     963           0 :     mRegistration->GetScope(mScope);
     964           0 :   }
     965             : 
     966             :   void
     967           0 :   StartListeningForEvents()
     968             :   {
     969           0 :     AssertIsOnMainThread();
     970           0 :     MOZ_ASSERT(!mListeningForEvents);
     971           0 :     MOZ_ASSERT(mWorkerPrivate);
     972           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     973           0 :     if (swm) {
     974             :       // FIXME(nsm): Maybe the function shouldn't take an explicit scope.
     975           0 :       swm->AddRegistrationEventListener(mScope, this);
     976           0 :       mListeningForEvents = true;
     977             :     }
     978           0 :   }
     979             : 
     980             :   void
     981           0 :   StopListeningForEvents()
     982             :   {
     983           0 :     AssertIsOnMainThread();
     984             : 
     985           0 :     MOZ_ASSERT(mListeningForEvents);
     986             : 
     987           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     988             : 
     989             :     // We aren't going to need this anymore and we shouldn't hold on since the
     990             :     // worker will go away soon.
     991           0 :     mWorkerPrivate = nullptr;
     992             : 
     993           0 :     if (swm) {
     994             :       // FIXME(nsm): Maybe the function shouldn't take an explicit scope.
     995           0 :       swm->RemoveRegistrationEventListener(mScope, this);
     996           0 :       mListeningForEvents = false;
     997             :     }
     998           0 :   }
     999             : 
    1000             :   // ServiceWorkerRegistrationListener
    1001             :   void
    1002             :   UpdateFound() override;
    1003             : 
    1004             :   void
    1005           0 :   TransitionWorker(WhichServiceWorker aWhichOne) override
    1006             :   {
    1007           0 :     AssertIsOnMainThread();
    1008           0 :     NS_WARNING("FIXME: Not implemented!");
    1009           0 :   }
    1010             : 
    1011             :   void
    1012           0 :   InvalidateWorkers(WhichServiceWorker aWhichOnes) override
    1013             :   {
    1014           0 :     AssertIsOnMainThread();
    1015             :     // FIXME(nsm);
    1016           0 :   }
    1017             : 
    1018             :   void
    1019           0 :   RegistrationRemoved() override
    1020             :   {
    1021           0 :     AssertIsOnMainThread();
    1022           0 :   }
    1023             : 
    1024             :   void
    1025           0 :   GetScope(nsAString& aScope) const override
    1026             :   {
    1027           0 :     aScope = mScope;
    1028           0 :   }
    1029             : 
    1030             :   ServiceWorkerRegistrationWorkerThread*
    1031           0 :   GetRegistration() const
    1032             :   {
    1033           0 :     if (mWorkerPrivate) {
    1034           0 :       mWorkerPrivate->AssertIsOnWorkerThread();
    1035             :     }
    1036           0 :     return mRegistration;
    1037             :   }
    1038             : 
    1039             :   void
    1040           0 :   ClearRegistration()
    1041             :   {
    1042           0 :     if (mWorkerPrivate) {
    1043           0 :       mWorkerPrivate->AssertIsOnWorkerThread();
    1044             :     }
    1045           0 :     mRegistration = nullptr;
    1046           0 :   }
    1047             : 
    1048             : private:
    1049           0 :   ~WorkerListener()
    1050           0 :   {
    1051           0 :     MOZ_ASSERT(!mListeningForEvents);
    1052           0 :   }
    1053             : };
    1054             : 
    1055           0 : NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistrationWorkerThread, ServiceWorkerRegistration)
    1056           0 : NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistrationWorkerThread, ServiceWorkerRegistration)
    1057             : 
    1058           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistrationWorkerThread)
    1059           0 : NS_INTERFACE_MAP_END_INHERITING(ServiceWorkerRegistration)
    1060             : 
    1061             : // Expanded macros since we need special behaviour to release the proxy.
    1062             : NS_IMPL_CYCLE_COLLECTION_CLASS(ServiceWorkerRegistrationWorkerThread)
    1063             : 
    1064           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServiceWorkerRegistrationWorkerThread,
    1065             :                                                   ServiceWorkerRegistration)
    1066           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPushManager)
    1067             : 
    1068           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1069             : 
    1070           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ServiceWorkerRegistrationWorkerThread,
    1071             :                                                 ServiceWorkerRegistration)
    1072           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPushManager)
    1073           0 :   tmp->ReleaseListener();
    1074           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1075             : 
    1076           0 : ServiceWorkerRegistrationWorkerThread::ServiceWorkerRegistrationWorkerThread(WorkerPrivate* aWorkerPrivate,
    1077           0 :                                                                              const nsAString& aScope)
    1078             :   : ServiceWorkerRegistration(nullptr, aScope)
    1079           0 :   , mWorkerPrivate(aWorkerPrivate)
    1080             : {
    1081           0 :   InitListener();
    1082           0 : }
    1083             : 
    1084           0 : ServiceWorkerRegistrationWorkerThread::~ServiceWorkerRegistrationWorkerThread()
    1085             : {
    1086           0 :   ReleaseListener();
    1087           0 :   MOZ_ASSERT(!mListener);
    1088           0 : }
    1089             : 
    1090             : already_AddRefed<workers::ServiceWorker>
    1091           0 : ServiceWorkerRegistrationWorkerThread::GetInstalling()
    1092             : {
    1093             :   // FIXME(nsm): Will be implemented after Bug 1113522.
    1094           0 :   return nullptr;
    1095             : }
    1096             : 
    1097             : already_AddRefed<ServiceWorker>
    1098           0 : ServiceWorkerRegistrationWorkerThread::GetWaiting()
    1099             : {
    1100             :   // FIXME(nsm): Will be implemented after Bug 1113522.
    1101           0 :   return nullptr;
    1102             : }
    1103             : 
    1104             : already_AddRefed<ServiceWorker>
    1105           0 : ServiceWorkerRegistrationWorkerThread::GetActive()
    1106             : {
    1107             :   // FIXME(nsm): Will be implemented after Bug 1113522.
    1108           0 :   return nullptr;
    1109             : }
    1110             : 
    1111             : already_AddRefed<Promise>
    1112           0 : ServiceWorkerRegistrationWorkerThread::Update(ErrorResult& aRv)
    1113             : {
    1114           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
    1115           0 :   MOZ_ASSERT(worker);
    1116           0 :   worker->AssertIsOnWorkerThread();
    1117             : 
    1118           0 :   RefPtr<Promise> promise = Promise::Create(worker->GlobalScope(), aRv);
    1119           0 :   if (aRv.Failed()) {
    1120           0 :     return nullptr;
    1121             :   }
    1122             : 
    1123             :   // Avoid infinite update loops by ignoring update() calls during top
    1124             :   // level script evaluation.  See:
    1125             :   // https://github.com/slightlyoff/ServiceWorker/issues/800
    1126           0 :   if (worker->LoadScriptAsPartOfLoadingServiceWorkerScript()) {
    1127           0 :     promise->MaybeResolveWithUndefined();
    1128           0 :     return promise.forget();
    1129             :   }
    1130             : 
    1131           0 :   RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, promise);
    1132           0 :   if (!proxy) {
    1133           0 :     aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
    1134           0 :     return nullptr;
    1135             :   }
    1136             : 
    1137           0 :   RefPtr<UpdateRunnable> r = new UpdateRunnable(proxy, mScope);
    1138           0 :   MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget()));
    1139             : 
    1140           0 :   return promise.forget();
    1141             : }
    1142             : 
    1143             : already_AddRefed<Promise>
    1144           0 : ServiceWorkerRegistrationWorkerThread::Unregister(ErrorResult& aRv)
    1145             : {
    1146           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
    1147           0 :   MOZ_ASSERT(worker);
    1148           0 :   worker->AssertIsOnWorkerThread();
    1149             : 
    1150           0 :   if (!worker->IsServiceWorker()) {
    1151             :     // For other workers, the registration probably originated from
    1152             :     // getRegistration(), so we may have to validate origin etc. Let's do this
    1153             :     // this later.
    1154           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    1155           0 :     return nullptr;
    1156             :   }
    1157             : 
    1158           0 :   RefPtr<Promise> promise = Promise::Create(worker->GlobalScope(), aRv);
    1159           0 :   if (aRv.Failed()) {
    1160           0 :     return nullptr;
    1161             :   }
    1162             : 
    1163           0 :   RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, promise);
    1164           0 :   if (!proxy) {
    1165           0 :     aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
    1166           0 :     return nullptr;
    1167             :   }
    1168             : 
    1169           0 :   RefPtr<StartUnregisterRunnable> r = new StartUnregisterRunnable(proxy, mScope);
    1170           0 :   MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget()));
    1171             : 
    1172           0 :   return promise.forget();
    1173             : }
    1174             : 
    1175             : void
    1176           0 : ServiceWorkerRegistrationWorkerThread::InitListener()
    1177             : {
    1178           0 :   MOZ_ASSERT(!mListener);
    1179           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
    1180           0 :   MOZ_ASSERT(worker);
    1181           0 :   worker->AssertIsOnWorkerThread();
    1182             : 
    1183           0 :   mListener = new WorkerListener(worker, this);
    1184           0 :   if (!HoldWorker(worker, Closing)) {
    1185           0 :     mListener = nullptr;
    1186           0 :     NS_WARNING("Could not add feature");
    1187           0 :     return;
    1188             :   }
    1189             : 
    1190             :   nsCOMPtr<nsIRunnable> r =
    1191           0 :     NewRunnableMethod("dom::WorkerListener::StartListeningForEvents",
    1192             :                       mListener,
    1193           0 :                       &WorkerListener::StartListeningForEvents);
    1194           0 :   MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget()));
    1195             : }
    1196             : 
    1197             : void
    1198           0 : ServiceWorkerRegistrationWorkerThread::ReleaseListener()
    1199             : {
    1200           0 :   if (!mListener) {
    1201           0 :     return;
    1202             :   }
    1203             : 
    1204             :   // We can assert worker here, because:
    1205             :   // 1) We always HoldWorker, so if the worker has shutdown already, we'll
    1206             :   //    have received Notify and removed it. If HoldWorker had failed,
    1207             :   //    mListener will be null and we won't reach here.
    1208             :   // 2) Otherwise, worker is still around even if we are going away.
    1209           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1210           0 :   ReleaseWorker();
    1211             : 
    1212           0 :   mListener->ClearRegistration();
    1213             : 
    1214             :   nsCOMPtr<nsIRunnable> r =
    1215           0 :     NewRunnableMethod("dom::WorkerListener::StopListeningForEvents",
    1216             :                       mListener,
    1217           0 :                       &WorkerListener::StopListeningForEvents);
    1218           0 :   MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(r.forget()));
    1219             : 
    1220           0 :   mListener = nullptr;
    1221           0 :   mWorkerPrivate = nullptr;
    1222             : }
    1223             : 
    1224             : bool
    1225           0 : ServiceWorkerRegistrationWorkerThread::Notify(Status aStatus)
    1226             : {
    1227           0 :   ReleaseListener();
    1228           0 :   return true;
    1229             : }
    1230             : 
    1231           0 : class FireUpdateFoundRunnable final : public WorkerRunnable
    1232             : {
    1233             :   RefPtr<WorkerListener> mListener;
    1234             : public:
    1235           0 :   FireUpdateFoundRunnable(WorkerPrivate* aWorkerPrivate,
    1236             :                           WorkerListener* aListener)
    1237           0 :     : WorkerRunnable(aWorkerPrivate)
    1238           0 :     , mListener(aListener)
    1239             :   {
    1240             :     // Need this assertion for now since runnables which modify busy count can
    1241             :     // only be dispatched from parent thread to worker thread and we don't deal
    1242             :     // with nested workers. SW threads can't be nested.
    1243           0 :     MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
    1244           0 :   }
    1245             : 
    1246             :   bool
    1247           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1248             :   {
    1249           0 :     MOZ_ASSERT(aWorkerPrivate);
    1250           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
    1251             : 
    1252           0 :     ServiceWorkerRegistrationWorkerThread* reg = mListener->GetRegistration();
    1253           0 :     if (reg) {
    1254           0 :       reg->DispatchTrustedEvent(NS_LITERAL_STRING("updatefound"));
    1255             :     }
    1256           0 :     return true;
    1257             :   }
    1258             : };
    1259             : 
    1260             : void
    1261           0 : WorkerListener::UpdateFound()
    1262             : {
    1263           0 :   AssertIsOnMainThread();
    1264           0 :   if (mWorkerPrivate) {
    1265             :     RefPtr<FireUpdateFoundRunnable> r =
    1266           0 :       new FireUpdateFoundRunnable(mWorkerPrivate, this);
    1267           0 :     Unused << NS_WARN_IF(!r->Dispatch());
    1268             :   }
    1269           0 : }
    1270             : 
    1271             : // Notification API extension.
    1272             : already_AddRefed<Promise>
    1273           0 : ServiceWorkerRegistrationWorkerThread::ShowNotification(JSContext* aCx,
    1274             :                                                         const nsAString& aTitle,
    1275             :                                                         const NotificationOptions& aOptions,
    1276             :                                                         ErrorResult& aRv)
    1277             : {
    1278             :   // Until Bug 1131324 exposes ServiceWorkerContainer on workers,
    1279             :   // ShowPersistentNotification() checks for valid active worker while it is
    1280             :   // also verifying scope so that we block the worker on the main thread only
    1281             :   // once.
    1282             :   RefPtr<Promise> p =
    1283           0 :     Notification::ShowPersistentNotification(aCx, mWorkerPrivate->GlobalScope(),
    1284           0 :                                              mScope, aTitle, aOptions, aRv);
    1285           0 :   if (NS_WARN_IF(aRv.Failed())) {
    1286           0 :     return nullptr;
    1287             :   }
    1288             : 
    1289           0 :   return p.forget();
    1290             : }
    1291             : 
    1292             : already_AddRefed<Promise>
    1293           0 : ServiceWorkerRegistrationWorkerThread::GetNotifications(const GetNotificationOptions& aOptions,
    1294             :                                                         ErrorResult& aRv)
    1295             : {
    1296           0 :   return Notification::WorkerGet(mWorkerPrivate, aOptions, mScope, aRv);
    1297             : }
    1298             : 
    1299             : already_AddRefed<PushManager>
    1300           0 : ServiceWorkerRegistrationWorkerThread::GetPushManager(JSContext* aCx, ErrorResult& aRv)
    1301             : {
    1302           0 :   if (!mPushManager) {
    1303           0 :     mPushManager = new PushManager(mScope);
    1304             :   }
    1305             : 
    1306           0 :   RefPtr<PushManager> ret = mPushManager;
    1307           0 :   return ret.forget();
    1308             : }
    1309             : 
    1310             : ////////////////////////////////////////////////////
    1311             : // Base class implementation
    1312             : 
    1313           0 : NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
    1314           0 : NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
    1315             : 
    1316           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistration)
    1317           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
    1318             : 
    1319           0 : ServiceWorkerRegistration::ServiceWorkerRegistration(nsPIDOMWindowInner* aWindow,
    1320           0 :                                                      const nsAString& aScope)
    1321             :   : DOMEventTargetHelper(aWindow)
    1322           0 :   , mScope(aScope)
    1323           0 : {}
    1324             : 
    1325             : JSObject*
    1326           0 : ServiceWorkerRegistration::WrapObject(JSContext* aCx,
    1327             :                                       JS::Handle<JSObject*> aGivenProto)
    1328             : {
    1329           0 :   return ServiceWorkerRegistrationBinding::Wrap(aCx, this, aGivenProto);
    1330             : }
    1331             : 
    1332             : /* static */ already_AddRefed<ServiceWorkerRegistration>
    1333           0 : ServiceWorkerRegistration::CreateForMainThread(nsPIDOMWindowInner* aWindow,
    1334             :                                                const nsAString& aScope)
    1335             : {
    1336           0 :   MOZ_ASSERT(aWindow);
    1337           0 :   MOZ_ASSERT(NS_IsMainThread());
    1338             : 
    1339             :   RefPtr<ServiceWorkerRegistration> registration =
    1340           0 :     new ServiceWorkerRegistrationMainThread(aWindow, aScope);
    1341             : 
    1342           0 :   return registration.forget();
    1343             : }
    1344             : 
    1345             : /* static */ already_AddRefed<ServiceWorkerRegistration>
    1346           0 : ServiceWorkerRegistration::CreateForWorker(workers::WorkerPrivate* aWorkerPrivate,
    1347             :                                            const nsAString& aScope)
    1348             : {
    1349           0 :   MOZ_ASSERT(aWorkerPrivate);
    1350           0 :   aWorkerPrivate->AssertIsOnWorkerThread();
    1351             : 
    1352             :   RefPtr<ServiceWorkerRegistration> registration =
    1353           0 :     new ServiceWorkerRegistrationWorkerThread(aWorkerPrivate, aScope);
    1354             : 
    1355           0 :   return registration.forget();
    1356             : }
    1357             : 
    1358             : } // dom namespace
    1359             : } // mozilla namespace

Generated by: LCOV version 1.13