LCOV - code coverage report
Current view: top level - dom/workers - ServiceWorkerClients.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 410 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 71 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 file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "ServiceWorkerClients.h"
       8             : 
       9             : #include "mozilla/dom/Promise.h"
      10             : #include "mozilla/dom/PromiseWorkerProxy.h"
      11             : 
      12             : #include "ServiceWorkerClient.h"
      13             : #include "ServiceWorkerManager.h"
      14             : #include "ServiceWorkerPrivate.h"
      15             : #include "ServiceWorkerWindowClient.h"
      16             : 
      17             : #include "WorkerPrivate.h"
      18             : #include "WorkerRunnable.h"
      19             : #include "WorkerScope.h"
      20             : 
      21             : #include "nsContentUtils.h"
      22             : #include "nsIBrowserDOMWindow.h"
      23             : #include "nsIDocShell.h"
      24             : #include "nsIDOMChromeWindow.h"
      25             : #include "nsIDOMWindow.h"
      26             : #include "nsIWebNavigation.h"
      27             : #include "nsIWebProgress.h"
      28             : #include "nsIWebProgressListener.h"
      29             : #include "nsIWindowMediator.h"
      30             : #include "nsIWindowWatcher.h"
      31             : #include "nsNetUtil.h"
      32             : #include "nsPIWindowWatcher.h"
      33             : #include "nsWindowWatcher.h"
      34             : #include "nsWeakReference.h"
      35             : 
      36             : #ifdef MOZ_WIDGET_ANDROID
      37             : #include "FennecJNIWrappers.h"
      38             : #endif
      39             : 
      40             : using namespace mozilla;
      41             : using namespace mozilla::dom;
      42             : using namespace mozilla::dom::workers;
      43             : 
      44           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerClients)
      45           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerClients)
      46           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ServiceWorkerClients, mWorkerScope)
      47             : 
      48           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClients)
      49           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      50           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      51           0 : NS_INTERFACE_MAP_END
      52             : 
      53           0 : ServiceWorkerClients::ServiceWorkerClients(ServiceWorkerGlobalScope* aWorkerScope)
      54           0 :   : mWorkerScope(aWorkerScope)
      55             : {
      56           0 :   MOZ_ASSERT(mWorkerScope);
      57           0 : }
      58             : 
      59             : JSObject*
      60           0 : ServiceWorkerClients::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
      61             : {
      62           0 :   return ClientsBinding::Wrap(aCx, this, aGivenProto);
      63             : }
      64             : 
      65             : namespace {
      66             : 
      67           0 : class GetRunnable final : public Runnable
      68             : {
      69           0 :   class ResolvePromiseWorkerRunnable final : public WorkerRunnable
      70             :   {
      71             :     RefPtr<PromiseWorkerProxy> mPromiseProxy;
      72             :     UniquePtr<ServiceWorkerClientInfo> mValue;
      73             :     nsresult mRv;
      74             : 
      75             :   public:
      76           0 :     ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate,
      77             :                                  PromiseWorkerProxy* aPromiseProxy,
      78             :                                  UniquePtr<ServiceWorkerClientInfo>&& aValue,
      79             :                                  nsresult aRv)
      80           0 :       : WorkerRunnable(aWorkerPrivate),
      81             :         mPromiseProxy(aPromiseProxy),
      82           0 :         mValue(Move(aValue)),
      83           0 :         mRv(Move(aRv))
      84             :     {
      85           0 :       AssertIsOnMainThread();
      86           0 :     }
      87             : 
      88             :     bool
      89           0 :     WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
      90             :     {
      91           0 :       MOZ_ASSERT(aWorkerPrivate);
      92           0 :       aWorkerPrivate->AssertIsOnWorkerThread();
      93             : 
      94           0 :       Promise* promise = mPromiseProxy->WorkerPromise();
      95           0 :       MOZ_ASSERT(promise);
      96             : 
      97           0 :       if (NS_FAILED(mRv)) {
      98           0 :         promise->MaybeReject(mRv);
      99           0 :       } else if (mValue) {
     100             :         RefPtr<ServiceWorkerWindowClient> windowClient =
     101           0 :           new ServiceWorkerWindowClient(promise->GetParentObject(), *mValue);
     102           0 :         promise->MaybeResolve(windowClient.get());
     103             :       } else {
     104           0 :         promise->MaybeResolveWithUndefined();
     105             :       }
     106           0 :       mPromiseProxy->CleanUp();
     107           0 :       return true;
     108             :     }
     109             :   };
     110             : 
     111             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     112             :   nsString mClientId;
     113             : public:
     114           0 :   GetRunnable(PromiseWorkerProxy* aPromiseProxy, const nsAString& aClientId)
     115           0 :     : mozilla::Runnable("GetRunnable")
     116             :     , mPromiseProxy(aPromiseProxy)
     117           0 :     , mClientId(aClientId)
     118             :   {
     119           0 :   }
     120             : 
     121             :   NS_IMETHOD
     122           0 :   Run() override
     123             :   {
     124           0 :     AssertIsOnMainThread();
     125             : 
     126           0 :     MutexAutoLock lock(mPromiseProxy->Lock());
     127           0 :     if (mPromiseProxy->CleanedUp()) {
     128           0 :       return NS_OK;
     129             :     }
     130             : 
     131           0 :     WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
     132           0 :     MOZ_ASSERT(workerPrivate);
     133             : 
     134           0 :     UniquePtr<ServiceWorkerClientInfo> result;
     135           0 :     ErrorResult rv;
     136             : 
     137           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     138           0 :     if (!swm) {
     139           0 :       rv = NS_ERROR_FAILURE;
     140             :     } else {
     141           0 :       result = swm->GetClient(workerPrivate->GetPrincipal(), mClientId, rv);
     142             :     }
     143             : 
     144             :     RefPtr<ResolvePromiseWorkerRunnable> r =
     145           0 :       new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
     146             :                                        mPromiseProxy, Move(result),
     147           0 :                                        rv.StealNSResult());
     148           0 :     rv.SuppressException();
     149             : 
     150           0 :     r->Dispatch();
     151           0 :     return NS_OK;
     152             :   }
     153             : };
     154             : 
     155           0 : class MatchAllRunnable final : public Runnable
     156             : {
     157           0 :   class ResolvePromiseWorkerRunnable final : public WorkerRunnable
     158             :   {
     159             :     RefPtr<PromiseWorkerProxy> mPromiseProxy;
     160             :     nsTArray<ServiceWorkerClientInfo> mValue;
     161             : 
     162             :   public:
     163           0 :     ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate,
     164             :                                  PromiseWorkerProxy* aPromiseProxy,
     165             :                                  nsTArray<ServiceWorkerClientInfo>& aValue)
     166           0 :       : WorkerRunnable(aWorkerPrivate),
     167           0 :         mPromiseProxy(aPromiseProxy)
     168             :     {
     169           0 :       AssertIsOnMainThread();
     170           0 :       mValue.SwapElements(aValue);
     171           0 :     }
     172             : 
     173             :     bool
     174           0 :     WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
     175             :     {
     176           0 :       MOZ_ASSERT(aWorkerPrivate);
     177           0 :       aWorkerPrivate->AssertIsOnWorkerThread();
     178             : 
     179           0 :       Promise* promise = mPromiseProxy->WorkerPromise();
     180           0 :       MOZ_ASSERT(promise);
     181             : 
     182           0 :       nsTArray<RefPtr<ServiceWorkerClient>> ret;
     183           0 :       for (size_t i = 0; i < mValue.Length(); i++) {
     184           0 :         ret.AppendElement(RefPtr<ServiceWorkerClient>(
     185           0 :               new ServiceWorkerWindowClient(promise->GetParentObject(),
     186           0 :                                             mValue.ElementAt(i))));
     187             :       }
     188             : 
     189           0 :       promise->MaybeResolve(ret);
     190           0 :       mPromiseProxy->CleanUp();
     191           0 :       return true;
     192             :     }
     193             :   };
     194             : 
     195             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     196             :   const nsCString mScope;
     197             :   const uint64_t mServiceWorkerID;
     198             :   const bool mIncludeUncontrolled;
     199             : public:
     200           0 :   MatchAllRunnable(PromiseWorkerProxy* aPromiseProxy,
     201             :                    const nsCString& aScope,
     202             :                    uint64_t aServiceWorkerID,
     203             :                    bool aIncludeUncontrolled)
     204           0 :     : mozilla::Runnable("MatchAllRunnable")
     205             :     , mPromiseProxy(aPromiseProxy)
     206             :     , mScope(aScope)
     207             :     , mServiceWorkerID(aServiceWorkerID)
     208           0 :     , mIncludeUncontrolled(aIncludeUncontrolled)
     209             :   {
     210           0 :     MOZ_ASSERT(mPromiseProxy);
     211           0 :   }
     212             : 
     213             :   NS_IMETHOD
     214           0 :   Run() override
     215             :   {
     216           0 :     AssertIsOnMainThread();
     217             : 
     218           0 :     MutexAutoLock lock(mPromiseProxy->Lock());
     219           0 :     if (mPromiseProxy->CleanedUp()) {
     220           0 :       return NS_OK;
     221             :     }
     222             : 
     223           0 :     nsTArray<ServiceWorkerClientInfo> result;
     224           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     225           0 :     if (swm) {
     226           0 :       swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(),
     227           0 :                          mScope, mServiceWorkerID, mIncludeUncontrolled,
     228           0 :                          result);
     229             :     }
     230             :     RefPtr<ResolvePromiseWorkerRunnable> r =
     231           0 :       new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
     232           0 :                                        mPromiseProxy, result);
     233             : 
     234           0 :     r->Dispatch();
     235           0 :     return NS_OK;
     236             :   }
     237             : };
     238             : 
     239           0 : class ResolveClaimRunnable final : public WorkerRunnable
     240             : {
     241             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     242             :   nsresult mResult;
     243             : 
     244             : public:
     245           0 :   ResolveClaimRunnable(WorkerPrivate* aWorkerPrivate,
     246             :                        PromiseWorkerProxy* aPromiseProxy,
     247             :                        nsresult aResult)
     248           0 :     : WorkerRunnable(aWorkerPrivate)
     249             :     , mPromiseProxy(aPromiseProxy)
     250           0 :     , mResult(aResult)
     251             :   {
     252           0 :     AssertIsOnMainThread();
     253           0 :   }
     254             : 
     255             :   bool
     256           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     257             :   {
     258           0 :     MOZ_ASSERT(aWorkerPrivate);
     259           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     260             : 
     261           0 :     RefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
     262           0 :     MOZ_ASSERT(promise);
     263             : 
     264           0 :     if (NS_SUCCEEDED(mResult)) {
     265           0 :       promise->MaybeResolveWithUndefined();
     266             :     } else {
     267           0 :       promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     268             :     }
     269             : 
     270           0 :     mPromiseProxy->CleanUp();
     271           0 :     return true;
     272             :   }
     273             : };
     274             : 
     275           0 : class ClaimRunnable final : public Runnable
     276             : {
     277             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     278             :   nsCString mScope;
     279             :   uint64_t mServiceWorkerID;
     280             : 
     281             : public:
     282           0 :   ClaimRunnable(PromiseWorkerProxy* aPromiseProxy, const nsCString& aScope)
     283           0 :     : mozilla::Runnable("ClaimRunnable")
     284             :     , mPromiseProxy(aPromiseProxy)
     285             :     , mScope(aScope)
     286             :     // Safe to call GetWorkerPrivate() since we are being called on the worker
     287             :     // thread via script (so no clean up has occured yet).
     288           0 :     , mServiceWorkerID(aPromiseProxy->GetWorkerPrivate()->ServiceWorkerID())
     289             :   {
     290           0 :     MOZ_ASSERT(aPromiseProxy);
     291           0 :   }
     292             : 
     293             :   NS_IMETHOD
     294           0 :   Run() override
     295             :   {
     296           0 :     MutexAutoLock lock(mPromiseProxy->Lock());
     297           0 :     if (mPromiseProxy->CleanedUp()) {
     298           0 :       return NS_OK;
     299             :     }
     300             : 
     301           0 :     WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
     302           0 :     MOZ_ASSERT(workerPrivate);
     303             : 
     304           0 :     nsresult rv = NS_OK;
     305           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     306           0 :     if (!swm) {
     307             :       // browser shutdown
     308           0 :       rv = NS_ERROR_FAILURE;
     309             :     } else {
     310           0 :       rv = swm->ClaimClients(workerPrivate->GetPrincipal(), mScope,
     311           0 :                              mServiceWorkerID);
     312             :     }
     313             : 
     314             :     RefPtr<ResolveClaimRunnable> r =
     315           0 :       new ResolveClaimRunnable(workerPrivate, mPromiseProxy, rv);
     316             : 
     317           0 :     r->Dispatch();
     318           0 :     return NS_OK;
     319             :   }
     320             : };
     321             : 
     322           0 : class ResolveOpenWindowRunnable final : public WorkerRunnable
     323             : {
     324             : public:
     325           0 :   ResolveOpenWindowRunnable(PromiseWorkerProxy* aPromiseProxy,
     326             :                             UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
     327             :                             const nsresult aStatus)
     328           0 :   : WorkerRunnable(aPromiseProxy->GetWorkerPrivate())
     329             :   , mPromiseProxy(aPromiseProxy)
     330           0 :   , mClientInfo(Move(aClientInfo))
     331           0 :   , mStatus(aStatus)
     332             :   {
     333           0 :     AssertIsOnMainThread();
     334           0 :     MOZ_ASSERT(aPromiseProxy);
     335           0 :   }
     336             : 
     337             :   bool
     338           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
     339             :   {
     340           0 :     MOZ_ASSERT(aWorkerPrivate);
     341           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     342             : 
     343           0 :     Promise* promise = mPromiseProxy->WorkerPromise();
     344           0 :     if (NS_WARN_IF(NS_FAILED(mStatus))) {
     345           0 :       promise->MaybeReject(mStatus);
     346           0 :     } else if (mClientInfo) {
     347             :       RefPtr<ServiceWorkerWindowClient> client =
     348           0 :         new ServiceWorkerWindowClient(promise->GetParentObject(),
     349           0 :                                       *mClientInfo);
     350           0 :       promise->MaybeResolve(client);
     351             :     } else {
     352           0 :       promise->MaybeResolve(JS::NullHandleValue);
     353             :     }
     354             : 
     355           0 :     mPromiseProxy->CleanUp();
     356           0 :     return true;
     357             :   }
     358             : 
     359             : private:
     360             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     361             :   UniquePtr<ServiceWorkerClientInfo> mClientInfo;
     362             :   const nsresult mStatus;
     363             : };
     364             : 
     365             : class WebProgressListener final : public nsIWebProgressListener,
     366             :                                   public nsSupportsWeakReference
     367             : {
     368             : public:
     369             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     370           0 :   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(WebProgressListener, nsIWebProgressListener)
     371             : 
     372           0 :   WebProgressListener(PromiseWorkerProxy* aPromiseProxy,
     373             :                       ServiceWorkerPrivate* aServiceWorkerPrivate,
     374             :                       nsPIDOMWindowOuter* aWindow,
     375             :                       nsIURI* aBaseURI)
     376           0 :   : mPromiseProxy(aPromiseProxy)
     377             :   , mServiceWorkerPrivate(aServiceWorkerPrivate)
     378             :   , mWindow(aWindow)
     379           0 :   , mBaseURI(aBaseURI)
     380             :   {
     381           0 :     MOZ_ASSERT(aPromiseProxy);
     382           0 :     MOZ_ASSERT(aServiceWorkerPrivate);
     383           0 :     MOZ_ASSERT(aWindow);
     384           0 :     MOZ_ASSERT(aWindow->IsOuterWindow());
     385           0 :     MOZ_ASSERT(aBaseURI);
     386           0 :     AssertIsOnMainThread();
     387             : 
     388           0 :     mServiceWorkerPrivate->StoreISupports(static_cast<nsIWebProgressListener*>(this));
     389           0 :   }
     390             : 
     391             :   NS_IMETHOD
     392           0 :   OnStateChange(nsIWebProgress* aWebProgress,
     393             :                 nsIRequest* aRequest,
     394             :                 uint32_t aStateFlags, nsresult aStatus) override
     395             :   {
     396           0 :     if (!(aStateFlags & STATE_IS_DOCUMENT) ||
     397           0 :          !(aStateFlags & (STATE_STOP | STATE_TRANSFERRING))) {
     398           0 :       return NS_OK;
     399             :     }
     400             : 
     401             :     // Our caller keeps a strong reference, so it is safe to remove the listener
     402             :     // from ServiceWorkerPrivate.
     403           0 :     mServiceWorkerPrivate->RemoveISupports(static_cast<nsIWebProgressListener*>(this));
     404           0 :     aWebProgress->RemoveProgressListener(this);
     405             : 
     406           0 :     MutexAutoLock lock(mPromiseProxy->Lock());
     407           0 :     if (mPromiseProxy->CleanedUp()) {
     408           0 :       return NS_OK;
     409             :     }
     410             : 
     411           0 :     nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
     412           0 :     UniquePtr<ServiceWorkerClientInfo> clientInfo;
     413           0 :     if (doc) {
     414             :       // Check same origin.
     415             :       nsCOMPtr<nsIScriptSecurityManager> securityManager =
     416           0 :         nsContentUtils::GetSecurityManager();
     417           0 :       nsresult rv = securityManager->CheckSameOriginURI(doc->GetOriginalURI(),
     418           0 :                                                         mBaseURI, false);
     419           0 :       if (NS_SUCCEEDED(rv)) {
     420           0 :         clientInfo.reset(new ServiceWorkerClientInfo(doc));
     421             :       }
     422             :     }
     423             : 
     424             :     RefPtr<ResolveOpenWindowRunnable> r =
     425             :       new ResolveOpenWindowRunnable(mPromiseProxy,
     426             :                                     Move(clientInfo),
     427           0 :                                     NS_OK);
     428           0 :     r->Dispatch();
     429             : 
     430           0 :     return NS_OK;
     431             :   }
     432             : 
     433             :   NS_IMETHOD
     434           0 :   OnProgressChange(nsIWebProgress* aWebProgress,
     435             :                    nsIRequest* aRequest,
     436             :                    int32_t aCurSelfProgress,
     437             :                    int32_t aMaxSelfProgress,
     438             :                    int32_t aCurTotalProgress,
     439             :                    int32_t aMaxTotalProgress) override
     440             :   {
     441           0 :     MOZ_ASSERT(false, "Unexpected notification.");
     442             :     return NS_OK;
     443             :   }
     444             : 
     445             :   NS_IMETHOD
     446           0 :   OnLocationChange(nsIWebProgress* aWebProgress,
     447             :                    nsIRequest* aRequest,
     448             :                    nsIURI* aLocation,
     449             :                    uint32_t aFlags) override
     450             :   {
     451           0 :     MOZ_ASSERT(false, "Unexpected notification.");
     452             :     return NS_OK;
     453             :   }
     454             : 
     455             :   NS_IMETHOD
     456           0 :   OnStatusChange(nsIWebProgress* aWebProgress,
     457             :                  nsIRequest* aRequest,
     458             :                  nsresult aStatus, const char16_t* aMessage) override
     459             :   {
     460           0 :     MOZ_ASSERT(false, "Unexpected notification.");
     461             :     return NS_OK;
     462             :   }
     463             : 
     464             :   NS_IMETHOD
     465           0 :   OnSecurityChange(nsIWebProgress* aWebProgress,
     466             :                    nsIRequest* aRequest,
     467             :                    uint32_t aState) override
     468             :   {
     469           0 :     MOZ_ASSERT(false, "Unexpected notification.");
     470             :     return NS_OK;
     471             :   }
     472             : 
     473             : private:
     474           0 :   ~WebProgressListener()
     475           0 :   { }
     476             : 
     477             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     478             :   RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
     479             :   nsCOMPtr<nsPIDOMWindowOuter> mWindow;
     480             :   nsCOMPtr<nsIURI> mBaseURI;
     481             : };
     482             : 
     483           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(WebProgressListener)
     484           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(WebProgressListener)
     485           0 : NS_IMPL_CYCLE_COLLECTION(WebProgressListener, mPromiseProxy,
     486             :                          mServiceWorkerPrivate, mWindow)
     487             : 
     488           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebProgressListener)
     489           0 :   NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
     490           0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     491           0 : NS_INTERFACE_MAP_END
     492             : 
     493             : class OpenWindowRunnable final : public Runnable
     494             :                                , public nsIObserver
     495             :                                , public nsSupportsWeakReference
     496             : {
     497             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     498             :   nsString mUrl;
     499             :   nsString mScope;
     500             : 
     501             : public:
     502             :   NS_DECL_ISUPPORTS_INHERITED
     503             :   // Note: |OpenWindowRunnable| cannot be cycle collected because it inherits
     504             :   // thread safe reference counting from |mozilla::Runnable|. On Fennec, we
     505             :   // might use |ServiceWorkerPrivate::StoreISupports| to keep this object alive
     506             :   // while waiting for an event from the observer service. As such, to avoid
     507             :   // creating a cycle that will leak, |OpenWindowRunnable| must not hold a strong
     508             :   // reference to |ServiceWorkerPrivate|.
     509             : 
     510           0 :   OpenWindowRunnable(PromiseWorkerProxy* aPromiseProxy,
     511             :                      const nsAString& aUrl,
     512             :                      const nsAString& aScope)
     513           0 :     : mozilla::Runnable("OpenWindowRunnable")
     514             :     , mPromiseProxy(aPromiseProxy)
     515             :     , mUrl(aUrl)
     516           0 :     , mScope(aScope)
     517             :   {
     518           0 :     MOZ_ASSERT(aPromiseProxy);
     519           0 :     MOZ_ASSERT(aPromiseProxy->GetWorkerPrivate());
     520           0 :     aPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
     521           0 :   }
     522             : 
     523             :   NS_IMETHOD
     524           0 :   Observe(nsISupports* aSubject, const char* aTopic, const char16_t* /* aData */) override
     525             :   {
     526           0 :     AssertIsOnMainThread();
     527             : 
     528           0 :     nsCString topic(aTopic);
     529           0 :     if (!topic.Equals(NS_LITERAL_CSTRING("BrowserChrome:Ready"))) {
     530           0 :       MOZ_ASSERT(false, "Unexpected topic.");
     531             :       return NS_ERROR_FAILURE;
     532             :     }
     533             : 
     534           0 :     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     535           0 :     NS_ENSURE_STATE(os);
     536           0 :     os->RemoveObserver(this, "BrowserChrome:Ready");
     537             : 
     538           0 :     RefPtr<ServiceWorkerPrivate> swp = GetServiceWorkerPrivate();
     539           0 :     NS_ENSURE_STATE(swp);
     540             : 
     541           0 :     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
     542           0 :     swp->RemoveISupports(static_cast<nsIObserver*>(this));
     543             : 
     544           0 :     return NS_OK;
     545             :   }
     546             : 
     547             :   NS_IMETHOD
     548           0 :   Run() override
     549             :   {
     550           0 :     AssertIsOnMainThread();
     551             : 
     552           0 :     MutexAutoLock lock(mPromiseProxy->Lock());
     553           0 :     if (mPromiseProxy->CleanedUp()) {
     554           0 :       return NS_OK;
     555             :     }
     556             : 
     557             : #ifdef MOZ_WIDGET_ANDROID
     558             :     // This fires an intent that will start launching Fennec and foreground it,
     559             :     // if necessary.
     560             :     if (jni::IsFennec()) {
     561             :       java::GeckoApp::LaunchOrBringToFront();
     562             :     }
     563             : #endif
     564             : 
     565           0 :     nsCOMPtr<nsPIDOMWindowOuter> window;
     566           0 :     nsresult rv = OpenWindow(getter_AddRefs(window));
     567           0 :     if (NS_SUCCEEDED(rv)) {
     568           0 :       MOZ_ASSERT(window);
     569             : 
     570           0 :       rv = nsContentUtils::DispatchFocusChromeEvent(window);
     571           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     572           0 :         return rv;
     573             :       }
     574             : 
     575           0 :       WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
     576           0 :       MOZ_ASSERT(workerPrivate);
     577             : 
     578           0 :       WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo();
     579           0 :       nsCOMPtr<nsIURI> baseURI;
     580           0 :       nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mHref);
     581           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     582           0 :         return NS_ERROR_FAILURE;
     583             :       }
     584             : 
     585           0 :       nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
     586           0 :       nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
     587             : 
     588           0 :       if (!webProgress) {
     589           0 :         return NS_ERROR_FAILURE;
     590             :       }
     591             : 
     592           0 :       RefPtr<ServiceWorkerPrivate> swp = GetServiceWorkerPrivate();
     593           0 :       NS_ENSURE_STATE(swp);
     594             : 
     595             :       nsCOMPtr<nsIWebProgressListener> listener =
     596           0 :         new WebProgressListener(mPromiseProxy, swp, window, baseURI);
     597             : 
     598           0 :       rv = webProgress->AddProgressListener(listener,
     599           0 :                                             nsIWebProgress::NOTIFY_STATE_DOCUMENT);
     600           0 :       MOZ_ASSERT(NS_SUCCEEDED(rv));
     601           0 :       return NS_OK;
     602             :     }
     603             : #ifdef MOZ_WIDGET_ANDROID
     604             :     else if (rv == NS_ERROR_NOT_AVAILABLE && jni::IsFennec()) {
     605             :       // We couldn't get a browser window, so Fennec must not be running.
     606             :       // Send an Intent to launch Fennec and wait for "BrowserChrome:Ready"
     607             :       // to try opening a window again.
     608             :       RefPtr<ServiceWorkerPrivate> swp = GetServiceWorkerPrivate();
     609             :       NS_ENSURE_STATE(swp);
     610             : 
     611             :       nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     612             :       NS_ENSURE_STATE(os);
     613             : 
     614             :       rv = os->AddObserver(this, "BrowserChrome:Ready", /* weakRef */ true);
     615             :       NS_ENSURE_SUCCESS(rv, rv);
     616             : 
     617             :       swp->StoreISupports(static_cast<nsIObserver*>(this));
     618             : 
     619             :       return NS_OK;
     620             :     }
     621             : #endif
     622             : 
     623             :     RefPtr<ResolveOpenWindowRunnable> resolveRunnable =
     624           0 :       new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv);
     625             : 
     626           0 :     Unused << NS_WARN_IF(!resolveRunnable->Dispatch());
     627             : 
     628           0 :     return NS_OK;
     629             :   }
     630             : 
     631             : private:
     632           0 :   ~OpenWindowRunnable()
     633           0 :   { }
     634             : 
     635             :   ServiceWorkerPrivate*
     636           0 :   GetServiceWorkerPrivate() const
     637             :   {
     638           0 :     AssertIsOnMainThread();
     639             : 
     640           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     641           0 :     if (!swm) {
     642             :       // browser shutdown
     643           0 :       return nullptr;
     644             :     }
     645             : 
     646           0 :     WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
     647           0 :     MOZ_ASSERT(workerPrivate);
     648             : 
     649           0 :     nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
     650           0 :     MOZ_DIAGNOSTIC_ASSERT(principal);
     651             : 
     652             :     RefPtr<ServiceWorkerRegistrationInfo> registration =
     653           0 :       swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
     654           0 :     if (NS_WARN_IF(!registration)) {
     655           0 :       return nullptr;
     656             :     }
     657             : 
     658             :     RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
     659           0 :       registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID());
     660           0 :     if (NS_WARN_IF(!serviceWorkerInfo)) {
     661           0 :       return nullptr;
     662             :     }
     663             : 
     664           0 :     return serviceWorkerInfo->WorkerPrivate();
     665             :   }
     666             : 
     667             :   nsresult
     668           0 :   OpenWindow(nsPIDOMWindowOuter** aWindow)
     669             :   {
     670           0 :     MOZ_DIAGNOSTIC_ASSERT(aWindow);
     671           0 :     WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
     672             : 
     673             :     // [[1. Let url be the result of parsing url with entry settings object's API
     674             :     //   base URL.]]
     675           0 :     nsCOMPtr<nsIURI> uri;
     676           0 :     WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo();
     677             : 
     678           0 :     nsCOMPtr<nsIURI> baseURI;
     679           0 :     nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mHref);
     680           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     681           0 :       return NS_ERROR_TYPE_ERR;
     682             :     }
     683             : 
     684           0 :     rv = NS_NewURI(getter_AddRefs(uri), mUrl, nullptr, baseURI);
     685           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     686           0 :       return NS_ERROR_TYPE_ERR;
     687             :     }
     688             : 
     689             :     // [[6.1 Open Window]]
     690           0 :     nsCOMPtr<nsIWindowMediator> wm = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID,
     691           0 :                                                    &rv);
     692           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     693           0 :       return rv;
     694             :     }
     695             : 
     696           0 :     if (XRE_IsContentProcess()) {
     697             :       // ContentProcess
     698             :       nsCOMPtr<nsIWindowWatcher> wwatch =
     699           0 :         do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     700           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     701           0 :         return rv;
     702             :       }
     703           0 :       nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
     704           0 :       NS_ENSURE_STATE(pwwatch);
     705             : 
     706           0 :       nsCString spec;
     707           0 :       rv = uri->GetSpec(spec);
     708           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     709           0 :         return rv;
     710             :       }
     711             : 
     712           0 :       nsCOMPtr<mozIDOMWindowProxy> newWindow;
     713           0 :       rv = pwwatch->OpenWindow2(nullptr,
     714             :                                 spec.get(),
     715             :                                 nullptr,
     716             :                                 nullptr,
     717             :                                 false, false, true, nullptr,
     718             :                                 // Not a spammy popup; we got permission, we swear!
     719             :                                 /* aIsPopupSpam = */ false,
     720             :                                 // Don't force noopener.  We're not passing in an
     721             :                                 // opener anyway, and we _do_ want the returned
     722             :                                 // window.
     723             :                                 /* aForceNoOpener = */ false,
     724             :                                 /* aLoadInfp = */ nullptr,
     725           0 :                                 getter_AddRefs(newWindow));
     726           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     727           0 :         return rv;
     728             :       }
     729           0 :       nsCOMPtr<nsPIDOMWindowOuter> pwindow = nsPIDOMWindowOuter::From(newWindow);
     730           0 :       pwindow.forget(aWindow);
     731           0 :       MOZ_DIAGNOSTIC_ASSERT(*aWindow);
     732           0 :       return NS_OK;
     733             :     }
     734             : 
     735             :     // Find the most recent browser window and open a new tab in it.
     736             :     nsCOMPtr<nsPIDOMWindowOuter> browserWindow =
     737           0 :       nsContentUtils::GetMostRecentNonPBWindow();
     738           0 :     if (!browserWindow) {
     739             :       // It is possible to be running without a browser window on Mac OS, so
     740             :       // we need to open a new chrome window.
     741             :       // TODO(catalinb): open new chrome window. Bug 1218080
     742           0 :       return NS_ERROR_NOT_AVAILABLE;
     743             :     }
     744             : 
     745           0 :     nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(browserWindow);
     746           0 :     if (NS_WARN_IF(!chromeWin)) {
     747           0 :       return NS_ERROR_FAILURE;
     748             :     }
     749             : 
     750           0 :     nsCOMPtr<nsIBrowserDOMWindow> bwin;
     751           0 :     chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
     752             : 
     753           0 :     if (NS_WARN_IF(!bwin)) {
     754           0 :       return NS_ERROR_FAILURE;
     755             :     }
     756             : 
     757           0 :     nsCOMPtr<nsIPrincipal> triggeringPrincipal = workerPrivate->GetPrincipal();
     758           0 :     MOZ_DIAGNOSTIC_ASSERT(triggeringPrincipal);
     759             : 
     760           0 :     nsCOMPtr<mozIDOMWindowProxy> win;
     761           0 :     rv = bwin->OpenURI(uri, nullptr,
     762             :                        nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
     763             :                        nsIBrowserDOMWindow::OPEN_NEW,
     764             :                        triggeringPrincipal,
     765           0 :                        getter_AddRefs(win));
     766           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     767           0 :       return rv;
     768             :     }
     769           0 :     NS_ENSURE_STATE(win);
     770             : 
     771           0 :     nsCOMPtr<nsPIDOMWindowOuter> pWin = nsPIDOMWindowOuter::From(win);
     772           0 :     pWin.forget(aWindow);
     773           0 :     MOZ_DIAGNOSTIC_ASSERT(*aWindow);
     774             : 
     775           0 :     return NS_OK;
     776             :   }
     777             : };
     778             : 
     779           0 : NS_IMPL_ADDREF_INHERITED(OpenWindowRunnable, Runnable)                                    \
     780           0 : NS_IMPL_RELEASE_INHERITED(OpenWindowRunnable, Runnable)
     781             : 
     782           0 : NS_INTERFACE_MAP_BEGIN(OpenWindowRunnable)
     783           0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     784           0 : NS_INTERFACE_MAP_ENTRY(nsIObserver)
     785           0 : NS_INTERFACE_MAP_ENTRY(nsIRunnable)
     786           0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
     787           0 : NS_INTERFACE_MAP_END
     788             : 
     789             : } // namespace
     790             : 
     791             : already_AddRefed<Promise>
     792           0 : ServiceWorkerClients::Get(const nsAString& aClientId, ErrorResult& aRv)
     793             : {
     794           0 :   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     795           0 :   MOZ_ASSERT(workerPrivate);
     796           0 :   workerPrivate->AssertIsOnWorkerThread();
     797             : 
     798           0 :   RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
     799           0 :   if (NS_WARN_IF(aRv.Failed())) {
     800           0 :     return nullptr;
     801             :   }
     802             : 
     803             :   RefPtr<PromiseWorkerProxy> promiseProxy =
     804           0 :     PromiseWorkerProxy::Create(workerPrivate, promise);
     805           0 :   if (!promiseProxy) {
     806           0 :     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     807           0 :     return promise.forget();
     808             :   }
     809             : 
     810             :   RefPtr<GetRunnable> r =
     811           0 :     new GetRunnable(promiseProxy, aClientId);
     812           0 :   MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
     813           0 :   return promise.forget();
     814             : }
     815             : 
     816             : already_AddRefed<Promise>
     817           0 : ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
     818             :                                ErrorResult& aRv)
     819             : {
     820           0 :   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     821           0 :   MOZ_ASSERT(workerPrivate);
     822           0 :   workerPrivate->AssertIsOnWorkerThread();
     823             : 
     824           0 :   nsString scope;
     825           0 :   mWorkerScope->GetScope(scope);
     826             : 
     827           0 :   if (aOptions.mType != ClientType::Window) {
     828           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     829           0 :     return nullptr;
     830             :   }
     831             : 
     832           0 :   RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
     833           0 :   if (NS_WARN_IF(aRv.Failed())) {
     834           0 :     return nullptr;
     835             :   }
     836             : 
     837             :   RefPtr<PromiseWorkerProxy> promiseProxy =
     838           0 :     PromiseWorkerProxy::Create(workerPrivate, promise);
     839           0 :   if (!promiseProxy) {
     840           0 :     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     841           0 :     return promise.forget();
     842             :   }
     843             : 
     844             :   RefPtr<MatchAllRunnable> r =
     845             :     new MatchAllRunnable(promiseProxy,
     846           0 :                          NS_ConvertUTF16toUTF8(scope),
     847           0 :                          workerPrivate->ServiceWorkerID(),
     848           0 :                          aOptions.mIncludeUncontrolled);
     849           0 :   MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
     850           0 :   return promise.forget();
     851             : }
     852             : 
     853             : already_AddRefed<Promise>
     854           0 : ServiceWorkerClients::OpenWindow(const nsAString& aUrl,
     855             :                                  ErrorResult& aRv)
     856             : {
     857           0 :   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     858           0 :   MOZ_ASSERT(workerPrivate);
     859             : 
     860           0 :   RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
     861           0 :   if (NS_WARN_IF(aRv.Failed())) {
     862           0 :     return nullptr;
     863             :   }
     864             : 
     865           0 :   if (aUrl.EqualsLiteral("about:blank")) {
     866           0 :     promise->MaybeReject(NS_ERROR_TYPE_ERR);
     867           0 :     return promise.forget();
     868             :   }
     869             : 
     870             :   // [[4. If this algorithm is not allowed to show a popup ..]]
     871             :   // In Gecko the service worker is allowed to show a popup only if the user
     872             :   // just clicked on a notification.
     873           0 :   if (!workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
     874           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     875           0 :     return promise.forget();
     876             :   }
     877             : 
     878             :   RefPtr<PromiseWorkerProxy> promiseProxy =
     879           0 :     PromiseWorkerProxy::Create(workerPrivate, promise);
     880             : 
     881           0 :   if (!promiseProxy) {
     882           0 :     return nullptr;
     883             :   }
     884             : 
     885           0 :   nsString scope;
     886           0 :   mWorkerScope->GetScope(scope);
     887             : 
     888             :   RefPtr<OpenWindowRunnable> r = new OpenWindowRunnable(promiseProxy,
     889           0 :                                                         aUrl, scope);
     890           0 :   MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
     891             : 
     892           0 :   return promise.forget();
     893             : }
     894             : 
     895             : already_AddRefed<Promise>
     896           0 : ServiceWorkerClients::Claim(ErrorResult& aRv)
     897             : {
     898           0 :   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     899           0 :   MOZ_ASSERT(workerPrivate);
     900             : 
     901           0 :   RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
     902           0 :   if (NS_WARN_IF(aRv.Failed())) {
     903           0 :     return nullptr;
     904             :   }
     905             : 
     906             :   RefPtr<PromiseWorkerProxy> promiseProxy =
     907           0 :     PromiseWorkerProxy::Create(workerPrivate, promise);
     908           0 :   if (!promiseProxy) {
     909           0 :     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     910           0 :     return promise.forget();
     911             :   }
     912             : 
     913           0 :   nsString scope;
     914           0 :   mWorkerScope->GetScope(scope);
     915             : 
     916             :   RefPtr<ClaimRunnable> runnable =
     917           0 :     new ClaimRunnable(promiseProxy, NS_ConvertUTF16toUTF8(scope));
     918             : 
     919           0 :   MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(runnable.forget()));
     920           0 :   return promise.forget();
     921             : }

Generated by: LCOV version 1.13