LCOV - code coverage report
Current view: top level - dom/push - PushManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 278 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 46 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 "mozilla/dom/PushManager.h"
       8             : 
       9             : #include "mozilla/Base64.h"
      10             : #include "mozilla/Preferences.h"
      11             : #include "mozilla/Services.h"
      12             : #include "mozilla/Unused.h"
      13             : #include "mozilla/dom/PushManagerBinding.h"
      14             : #include "mozilla/dom/PushSubscription.h"
      15             : #include "mozilla/dom/PushSubscriptionOptionsBinding.h"
      16             : #include "mozilla/dom/PushUtil.h"
      17             : 
      18             : #include "mozilla/dom/Promise.h"
      19             : #include "mozilla/dom/PromiseWorkerProxy.h"
      20             : 
      21             : #include "nsIGlobalObject.h"
      22             : #include "nsIPermissionManager.h"
      23             : #include "nsIPrincipal.h"
      24             : #include "nsIPushService.h"
      25             : 
      26             : #include "nsComponentManagerUtils.h"
      27             : #include "nsContentUtils.h"
      28             : 
      29             : #include "WorkerRunnable.h"
      30             : #include "WorkerPrivate.h"
      31             : #include "WorkerScope.h"
      32             : 
      33             : namespace mozilla {
      34             : namespace dom {
      35             : 
      36             : using namespace workers;
      37             : 
      38             : namespace {
      39             : 
      40             : nsresult
      41           0 : GetPermissionState(nsIPrincipal* aPrincipal,
      42             :                    PushPermissionState& aState)
      43             : {
      44             :   nsCOMPtr<nsIPermissionManager> permManager =
      45           0 :     mozilla::services::GetPermissionManager();
      46             : 
      47           0 :   if (!permManager) {
      48           0 :     return NS_ERROR_FAILURE;
      49             :   }
      50           0 :   uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
      51           0 :   nsresult rv = permManager->TestExactPermissionFromPrincipal(
      52             :                   aPrincipal,
      53             :                   "desktop-notification",
      54           0 :                   &permission);
      55           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
      56           0 :     return rv;
      57             :   }
      58             : 
      59           0 :   if (permission == nsIPermissionManager::ALLOW_ACTION ||
      60           0 :       Preferences::GetBool("dom.push.testing.ignorePermission", false)) {
      61           0 :     aState = PushPermissionState::Granted;
      62           0 :   } else if (permission == nsIPermissionManager::DENY_ACTION) {
      63           0 :     aState = PushPermissionState::Denied;
      64             :   } else {
      65           0 :     aState = PushPermissionState::Prompt;
      66             :   }
      67             : 
      68           0 :   return NS_OK;
      69             : }
      70             : 
      71             : // A helper class that frees an `nsIPushSubscription` key buffer when it
      72             : // goes out of scope.
      73             : class MOZ_RAII AutoFreeKeyBuffer final
      74             : {
      75             :   uint8_t** mKeyBuffer;
      76             : 
      77             : public:
      78           0 :   explicit AutoFreeKeyBuffer(uint8_t** aKeyBuffer)
      79           0 :     : mKeyBuffer(aKeyBuffer)
      80             :   {
      81           0 :     MOZ_ASSERT(mKeyBuffer);
      82           0 :   }
      83             : 
      84           0 :   ~AutoFreeKeyBuffer()
      85           0 :   {
      86           0 :     NS_Free(*mKeyBuffer);
      87           0 :   }
      88             : };
      89             : 
      90             : // Copies a subscription key buffer into an array.
      91             : nsresult
      92           0 : CopySubscriptionKeyToArray(nsIPushSubscription* aSubscription,
      93             :                            const nsAString& aKeyName,
      94             :                            nsTArray<uint8_t>& aKey)
      95             : {
      96           0 :   uint8_t* keyBuffer = nullptr;
      97           0 :   AutoFreeKeyBuffer autoFree(&keyBuffer);
      98             : 
      99             :   uint32_t keyLen;
     100           0 :   nsresult rv = aSubscription->GetKey(aKeyName, &keyLen, &keyBuffer);
     101           0 :   if (NS_FAILED(rv)) {
     102           0 :     return rv;
     103             :   }
     104           0 :   if (!aKey.SetCapacity(keyLen, fallible) ||
     105           0 :       !aKey.InsertElementsAt(0, keyBuffer, keyLen, fallible)) {
     106           0 :     return NS_ERROR_OUT_OF_MEMORY;
     107             :   }
     108           0 :   return NS_OK;
     109             : }
     110             : 
     111             : nsresult
     112           0 : GetSubscriptionParams(nsIPushSubscription* aSubscription,
     113             :                       nsAString& aEndpoint,
     114             :                       nsTArray<uint8_t>& aRawP256dhKey,
     115             :                       nsTArray<uint8_t>& aAuthSecret,
     116             :                       nsTArray<uint8_t>& aAppServerKey)
     117             : {
     118           0 :   if (!aSubscription) {
     119           0 :     return NS_OK;
     120             :   }
     121             : 
     122           0 :   nsresult rv = aSubscription->GetEndpoint(aEndpoint);
     123           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     124           0 :     return rv;
     125             :   }
     126             : 
     127           0 :   rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("p256dh"),
     128           0 :                                   aRawP256dhKey);
     129           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     130           0 :     return rv;
     131             :   }
     132           0 :   rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("auth"),
     133           0 :                                   aAuthSecret);
     134           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     135           0 :     return rv;
     136             :   }
     137           0 :   rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("appServer"),
     138           0 :                                   aAppServerKey);
     139           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     140           0 :     return rv;
     141             :   }
     142             : 
     143           0 :   return NS_OK;
     144             : }
     145             : 
     146             : class GetSubscriptionResultRunnable final : public WorkerRunnable
     147             : {
     148             : public:
     149           0 :   GetSubscriptionResultRunnable(WorkerPrivate* aWorkerPrivate,
     150             :                                 already_AddRefed<PromiseWorkerProxy>&& aProxy,
     151             :                                 nsresult aStatus,
     152             :                                 const nsAString& aEndpoint,
     153             :                                 const nsAString& aScope,
     154             :                                 nsTArray<uint8_t>&& aRawP256dhKey,
     155             :                                 nsTArray<uint8_t>&& aAuthSecret,
     156             :                                 nsTArray<uint8_t>&& aAppServerKey)
     157           0 :     : WorkerRunnable(aWorkerPrivate)
     158           0 :     , mProxy(Move(aProxy))
     159             :     , mStatus(aStatus)
     160             :     , mEndpoint(aEndpoint)
     161             :     , mScope(aScope)
     162           0 :     , mRawP256dhKey(Move(aRawP256dhKey))
     163           0 :     , mAuthSecret(Move(aAuthSecret))
     164           0 :     , mAppServerKey(Move(aAppServerKey))
     165           0 :   { }
     166             : 
     167             :   bool
     168           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     169             :   {
     170           0 :     RefPtr<Promise> promise = mProxy->WorkerPromise();
     171           0 :     if (NS_SUCCEEDED(mStatus)) {
     172           0 :       if (mEndpoint.IsEmpty()) {
     173           0 :         promise->MaybeResolve(JS::NullHandleValue);
     174             :       } else {
     175             :         RefPtr<PushSubscription> sub =
     176             :             new PushSubscription(nullptr, mEndpoint, mScope,
     177           0 :                                  Move(mRawP256dhKey), Move(mAuthSecret),
     178           0 :                                  Move(mAppServerKey));
     179           0 :         promise->MaybeResolve(sub);
     180             :       }
     181           0 :     } else if (NS_ERROR_GET_MODULE(mStatus) == NS_ERROR_MODULE_DOM_PUSH ) {
     182           0 :       promise->MaybeReject(mStatus);
     183             :     } else {
     184           0 :       promise->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
     185             :     }
     186             : 
     187           0 :     mProxy->CleanUp();
     188             : 
     189           0 :     return true;
     190             :   }
     191             : private:
     192           0 :   ~GetSubscriptionResultRunnable()
     193           0 :   {}
     194             : 
     195             :   RefPtr<PromiseWorkerProxy> mProxy;
     196             :   nsresult mStatus;
     197             :   nsString mEndpoint;
     198             :   nsString mScope;
     199             :   nsTArray<uint8_t> mRawP256dhKey;
     200             :   nsTArray<uint8_t> mAuthSecret;
     201             :   nsTArray<uint8_t> mAppServerKey;
     202             : };
     203             : 
     204             : class GetSubscriptionCallback final : public nsIPushSubscriptionCallback
     205             : {
     206             : public:
     207             :   NS_DECL_ISUPPORTS
     208             : 
     209           0 :   explicit GetSubscriptionCallback(PromiseWorkerProxy* aProxy,
     210             :                                    const nsAString& aScope)
     211           0 :     : mProxy(aProxy)
     212           0 :     , mScope(aScope)
     213           0 :   {}
     214             : 
     215             :   NS_IMETHOD
     216           0 :   OnPushSubscription(nsresult aStatus,
     217             :                      nsIPushSubscription* aSubscription) override
     218             :   {
     219           0 :     AssertIsOnMainThread();
     220           0 :     MOZ_ASSERT(mProxy, "OnPushSubscription() called twice?");
     221             : 
     222           0 :     MutexAutoLock lock(mProxy->Lock());
     223           0 :     if (mProxy->CleanedUp()) {
     224           0 :       return NS_OK;
     225             :     }
     226             : 
     227           0 :     nsAutoString endpoint;
     228           0 :     nsTArray<uint8_t> rawP256dhKey, authSecret, appServerKey;
     229           0 :     if (NS_SUCCEEDED(aStatus)) {
     230             :       aStatus = GetSubscriptionParams(aSubscription, endpoint, rawP256dhKey,
     231           0 :                                       authSecret, appServerKey);
     232             :     }
     233             : 
     234           0 :     WorkerPrivate* worker = mProxy->GetWorkerPrivate();
     235             :     RefPtr<GetSubscriptionResultRunnable> r =
     236             :       new GetSubscriptionResultRunnable(worker,
     237           0 :                                         mProxy.forget(),
     238             :                                         aStatus,
     239             :                                         endpoint,
     240             :                                         mScope,
     241             :                                         Move(rawP256dhKey),
     242             :                                         Move(authSecret),
     243           0 :                                         Move(appServerKey));
     244           0 :     MOZ_ALWAYS_TRUE(r->Dispatch());
     245             : 
     246           0 :     return NS_OK;
     247             :   }
     248             : 
     249             :   // Convenience method for use in this file.
     250             :   void
     251           0 :   OnPushSubscriptionError(nsresult aStatus)
     252             :   {
     253           0 :     Unused << NS_WARN_IF(NS_FAILED(
     254             :         OnPushSubscription(aStatus, nullptr)));
     255           0 :   }
     256             : 
     257             : protected:
     258           0 :   ~GetSubscriptionCallback()
     259           0 :   {}
     260             : 
     261             : private:
     262             :   RefPtr<PromiseWorkerProxy> mProxy;
     263             :   nsString mScope;
     264             : };
     265             : 
     266           0 : NS_IMPL_ISUPPORTS(GetSubscriptionCallback, nsIPushSubscriptionCallback)
     267             : 
     268             : class GetSubscriptionRunnable final : public Runnable
     269             : {
     270             : public:
     271           0 :   GetSubscriptionRunnable(PromiseWorkerProxy* aProxy,
     272             :                           const nsAString& aScope,
     273             :                           PushManager::SubscriptionAction aAction,
     274             :                           nsTArray<uint8_t>&& aAppServerKey)
     275           0 :     : Runnable("dom::GetSubscriptionRunnable")
     276             :     , mProxy(aProxy)
     277             :     , mScope(aScope)
     278             :     , mAction(aAction)
     279           0 :     , mAppServerKey(Move(aAppServerKey))
     280           0 :   {}
     281             : 
     282             :   NS_IMETHOD
     283           0 :   Run() override
     284             :   {
     285           0 :     AssertIsOnMainThread();
     286             : 
     287           0 :     nsCOMPtr<nsIPrincipal> principal;
     288             : 
     289             :     {
     290             :       // Bug 1228723: If permission is revoked or an error occurs, the
     291             :       // subscription callback will be called synchronously. This causes
     292             :       // `GetSubscriptionCallback::OnPushSubscription` to deadlock when
     293             :       // it tries to acquire the lock.
     294           0 :       MutexAutoLock lock(mProxy->Lock());
     295           0 :       if (mProxy->CleanedUp()) {
     296           0 :         return NS_OK;
     297             :       }
     298           0 :       principal = mProxy->GetWorkerPrivate()->GetPrincipal();
     299             :     }
     300             : 
     301           0 :     MOZ_ASSERT(principal);
     302             : 
     303           0 :     RefPtr<GetSubscriptionCallback> callback = new GetSubscriptionCallback(mProxy, mScope);
     304             : 
     305             :     PushPermissionState state;
     306           0 :     nsresult rv = GetPermissionState(principal, state);
     307           0 :     if (NS_FAILED(rv)) {
     308           0 :       callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
     309           0 :       return NS_OK;
     310             :     }
     311             : 
     312           0 :     if (state != PushPermissionState::Granted) {
     313           0 :       if (mAction == PushManager::GetSubscriptionAction) {
     314           0 :         callback->OnPushSubscriptionError(NS_OK);
     315           0 :         return NS_OK;
     316             :       }
     317           0 :       callback->OnPushSubscriptionError(NS_ERROR_DOM_PUSH_DENIED_ERR);
     318           0 :       return NS_OK;
     319             :     }
     320             : 
     321             :     nsCOMPtr<nsIPushService> service =
     322           0 :       do_GetService("@mozilla.org/push/Service;1");
     323           0 :     if (NS_WARN_IF(!service)) {
     324           0 :       callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
     325           0 :       return NS_OK;
     326             :     }
     327             : 
     328           0 :     if (mAction == PushManager::SubscribeAction) {
     329           0 :       if (mAppServerKey.IsEmpty()) {
     330           0 :         rv = service->Subscribe(mScope, principal, callback);
     331             :       } else {
     332           0 :         rv = service->SubscribeWithKey(mScope, principal,
     333           0 :                                        mAppServerKey.Length(),
     334           0 :                                        mAppServerKey.Elements(), callback);
     335             :       }
     336             :     } else {
     337           0 :       MOZ_ASSERT(mAction == PushManager::GetSubscriptionAction);
     338           0 :       rv = service->GetSubscription(mScope, principal, callback);
     339             :     }
     340             : 
     341           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     342           0 :       callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
     343           0 :       return NS_OK;
     344             :     }
     345             : 
     346           0 :     return NS_OK;
     347             :   }
     348             : 
     349             : private:
     350           0 :   ~GetSubscriptionRunnable()
     351           0 :   {}
     352             : 
     353             :   RefPtr<PromiseWorkerProxy> mProxy;
     354             :   nsString mScope;
     355             :   PushManager::SubscriptionAction mAction;
     356             :   nsTArray<uint8_t> mAppServerKey;
     357             : };
     358             : 
     359             : class PermissionResultRunnable final : public WorkerRunnable
     360             : {
     361             : public:
     362           0 :   PermissionResultRunnable(PromiseWorkerProxy *aProxy,
     363             :                            nsresult aStatus,
     364             :                            PushPermissionState aState)
     365           0 :     : WorkerRunnable(aProxy->GetWorkerPrivate())
     366             :     , mProxy(aProxy)
     367             :     , mStatus(aStatus)
     368           0 :     , mState(aState)
     369             :   {
     370           0 :     AssertIsOnMainThread();
     371           0 :   }
     372             : 
     373             :   bool
     374           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     375             :   {
     376           0 :     MOZ_ASSERT(aWorkerPrivate);
     377           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     378             : 
     379           0 :     RefPtr<Promise> promise = mProxy->WorkerPromise();
     380           0 :     if (NS_SUCCEEDED(mStatus)) {
     381           0 :       promise->MaybeResolve(mState);
     382             :     } else {
     383           0 :       promise->MaybeReject(aCx, JS::UndefinedHandleValue);
     384             :     }
     385             : 
     386           0 :     mProxy->CleanUp();
     387             : 
     388           0 :     return true;
     389             :   }
     390             : 
     391             : private:
     392           0 :   ~PermissionResultRunnable()
     393           0 :   {}
     394             : 
     395             :   RefPtr<PromiseWorkerProxy> mProxy;
     396             :   nsresult mStatus;
     397             :   PushPermissionState mState;
     398             : };
     399             : 
     400             : class PermissionStateRunnable final : public Runnable
     401             : {
     402             : public:
     403           0 :   explicit PermissionStateRunnable(PromiseWorkerProxy* aProxy)
     404           0 :     : Runnable("dom::PermissionStateRunnable")
     405           0 :     , mProxy(aProxy)
     406           0 :   {}
     407             : 
     408             :   NS_IMETHOD
     409           0 :   Run() override
     410             :   {
     411           0 :     AssertIsOnMainThread();
     412           0 :     MutexAutoLock lock(mProxy->Lock());
     413           0 :     if (mProxy->CleanedUp()) {
     414           0 :       return NS_OK;
     415             :     }
     416             : 
     417             :     PushPermissionState state;
     418           0 :     nsresult rv = GetPermissionState(
     419           0 :       mProxy->GetWorkerPrivate()->GetPrincipal(),
     420             :       state
     421           0 :     );
     422             : 
     423             :     RefPtr<PermissionResultRunnable> r =
     424           0 :       new PermissionResultRunnable(mProxy, rv, state);
     425           0 :     MOZ_ALWAYS_TRUE(r->Dispatch());
     426             : 
     427           0 :     return NS_OK;
     428             :   }
     429             : 
     430             : private:
     431           0 :   ~PermissionStateRunnable()
     432           0 :   {}
     433             : 
     434             :   RefPtr<PromiseWorkerProxy> mProxy;
     435             : };
     436             : 
     437             : } // anonymous namespace
     438             : 
     439           0 : PushManager::PushManager(nsIGlobalObject* aGlobal, PushManagerImpl* aImpl)
     440             :   : mGlobal(aGlobal)
     441           0 :   , mImpl(aImpl)
     442             : {
     443           0 :   AssertIsOnMainThread();
     444           0 :   MOZ_ASSERT(aImpl);
     445           0 : }
     446             : 
     447           0 : PushManager::PushManager(const nsAString& aScope)
     448           0 :   : mScope(aScope)
     449             : {
     450             : #ifdef DEBUG
     451             :   // There's only one global on a worker, so we don't need to pass a global
     452             :   // object to the constructor.
     453           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     454           0 :   MOZ_ASSERT(worker);
     455           0 :   worker->AssertIsOnWorkerThread();
     456             : #endif
     457           0 : }
     458             : 
     459           0 : PushManager::~PushManager()
     460           0 : {}
     461             : 
     462           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushManager, mGlobal, mImpl)
     463           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(PushManager)
     464           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(PushManager)
     465           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushManager)
     466           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     467           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     468           0 : NS_INTERFACE_MAP_END
     469             : 
     470             : JSObject*
     471           0 : PushManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     472             : {
     473           0 :   return PushManagerBinding::Wrap(aCx, this, aGivenProto);
     474             : }
     475             : 
     476             : // static
     477             : already_AddRefed<PushManager>
     478           0 : PushManager::Constructor(GlobalObject& aGlobal,
     479             :                          const nsAString& aScope,
     480             :                          ErrorResult& aRv)
     481             : {
     482           0 :   if (!NS_IsMainThread()) {
     483           0 :     RefPtr<PushManager> ret = new PushManager(aScope);
     484           0 :     return ret.forget();
     485             :   }
     486             : 
     487           0 :   RefPtr<PushManagerImpl> impl = PushManagerImpl::Constructor(aGlobal,
     488             :                                                               aGlobal.Context(),
     489           0 :                                                               aScope, aRv);
     490           0 :   if (aRv.Failed()) {
     491           0 :     return nullptr;
     492             :   }
     493             : 
     494           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
     495           0 :   RefPtr<PushManager> ret = new PushManager(global, impl);
     496             : 
     497           0 :   return ret.forget();
     498             : }
     499             : 
     500             : already_AddRefed<Promise>
     501           0 : PushManager::Subscribe(const PushSubscriptionOptionsInit& aOptions,
     502             :                        ErrorResult& aRv)
     503             : {
     504           0 :   if (mImpl) {
     505           0 :     MOZ_ASSERT(NS_IsMainThread());
     506           0 :     return mImpl->Subscribe(aOptions, aRv);
     507             :   }
     508             : 
     509           0 :   return PerformSubscriptionActionFromWorker(SubscribeAction, aOptions, aRv);
     510             : }
     511             : 
     512             : already_AddRefed<Promise>
     513           0 : PushManager::GetSubscription(ErrorResult& aRv)
     514             : {
     515           0 :   if (mImpl) {
     516           0 :     MOZ_ASSERT(NS_IsMainThread());
     517           0 :     return mImpl->GetSubscription(aRv);
     518             :   }
     519             : 
     520           0 :   return PerformSubscriptionActionFromWorker(GetSubscriptionAction, aRv);
     521             : }
     522             : 
     523             : already_AddRefed<Promise>
     524           0 : PushManager::PermissionState(const PushSubscriptionOptionsInit& aOptions,
     525             :                              ErrorResult& aRv)
     526             : {
     527           0 :   if (mImpl) {
     528           0 :     MOZ_ASSERT(NS_IsMainThread());
     529           0 :     return mImpl->PermissionState(aOptions, aRv);
     530             :   }
     531             : 
     532           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     533           0 :   MOZ_ASSERT(worker);
     534           0 :   worker->AssertIsOnWorkerThread();
     535             : 
     536           0 :   nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
     537           0 :   RefPtr<Promise> p = Promise::Create(global, aRv);
     538           0 :   if (NS_WARN_IF(aRv.Failed())) {
     539           0 :     return nullptr;
     540             :   }
     541             : 
     542           0 :   RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
     543           0 :   if (!proxy) {
     544           0 :     p->MaybeReject(worker->GetJSContext(), JS::UndefinedHandleValue);
     545           0 :     return p.forget();
     546             :   }
     547             : 
     548             :   RefPtr<PermissionStateRunnable> r =
     549           0 :     new PermissionStateRunnable(proxy);
     550           0 :   NS_DispatchToMainThread(r);
     551             : 
     552           0 :   return p.forget();
     553             : }
     554             : 
     555             : already_AddRefed<Promise>
     556           0 : PushManager::PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
     557             :                                                  ErrorResult& aRv)
     558             : {
     559           0 :   PushSubscriptionOptionsInit options;
     560           0 :   return PerformSubscriptionActionFromWorker(aAction, options, aRv);
     561             : }
     562             : 
     563             : already_AddRefed<Promise>
     564           0 : PushManager::PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
     565             :                                                  const PushSubscriptionOptionsInit& aOptions,
     566             :                                                  ErrorResult& aRv)
     567             : {
     568           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     569           0 :   MOZ_ASSERT(worker);
     570           0 :   worker->AssertIsOnWorkerThread();
     571             : 
     572           0 :   nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
     573           0 :   RefPtr<Promise> p = Promise::Create(global, aRv);
     574           0 :   if (NS_WARN_IF(aRv.Failed())) {
     575           0 :     return nullptr;
     576             :   }
     577             : 
     578           0 :   RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
     579           0 :   if (!proxy) {
     580           0 :     p->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
     581           0 :     return p.forget();
     582             :   }
     583             : 
     584           0 :   nsTArray<uint8_t> appServerKey;
     585           0 :   if (!aOptions.mApplicationServerKey.IsNull()) {
     586           0 :     nsresult rv = NormalizeAppServerKey(aOptions.mApplicationServerKey.Value(),
     587           0 :                                         appServerKey);
     588           0 :     if (NS_FAILED(rv)) {
     589           0 :       p->MaybeReject(rv);
     590           0 :       return p.forget();
     591             :     }
     592             :   }
     593             : 
     594             :   RefPtr<GetSubscriptionRunnable> r =
     595           0 :     new GetSubscriptionRunnable(proxy, mScope, aAction, Move(appServerKey));
     596           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
     597             : 
     598           0 :   return p.forget();
     599             : }
     600             : 
     601             : nsresult
     602           0 : PushManager::NormalizeAppServerKey(const OwningArrayBufferViewOrArrayBufferOrString& aSource,
     603             :                                    nsTArray<uint8_t>& aAppServerKey)
     604             : {
     605           0 :   if (aSource.IsString()) {
     606           0 :     NS_ConvertUTF16toUTF8 base64Key(aSource.GetAsString());
     607           0 :     FallibleTArray<uint8_t> decodedKey;
     608             :     nsresult rv = Base64URLDecode(base64Key,
     609             :                                   Base64URLDecodePaddingPolicy::Reject,
     610           0 :                                   decodedKey);
     611           0 :     if (NS_FAILED(rv)) {
     612           0 :       return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
     613             :     }
     614           0 :     aAppServerKey = decodedKey;
     615           0 :   } else if (aSource.IsArrayBuffer()) {
     616           0 :     if (!PushUtil::CopyArrayBufferToArray(aSource.GetAsArrayBuffer(),
     617             :                                          aAppServerKey)) {
     618           0 :       return NS_ERROR_DOM_PUSH_INVALID_KEY_ERR;
     619             :     }
     620           0 :   } else if (aSource.IsArrayBufferView()) {
     621           0 :     if (!PushUtil::CopyArrayBufferViewToArray(aSource.GetAsArrayBufferView(),
     622             :                                               aAppServerKey)) {
     623           0 :       return NS_ERROR_DOM_PUSH_INVALID_KEY_ERR;
     624             :     }
     625             :   } else {
     626           0 :     MOZ_CRASH("Uninitialized union: expected string, buffer, or view");
     627             :   }
     628           0 :   if (aAppServerKey.IsEmpty()) {
     629           0 :     return NS_ERROR_DOM_PUSH_INVALID_KEY_ERR;
     630             :   }
     631           0 :   return NS_OK;
     632             : }
     633             : 
     634             : } // namespace dom
     635             : } // namespace mozilla

Generated by: LCOV version 1.13