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

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "mozilla/dom/PushSubscription.h"
       6             : 
       7             : #include "nsIPushService.h"
       8             : #include "nsIScriptObjectPrincipal.h"
       9             : 
      10             : #include "mozilla/Base64.h"
      11             : #include "mozilla/Unused.h"
      12             : 
      13             : #include "mozilla/dom/Promise.h"
      14             : #include "mozilla/dom/PromiseWorkerProxy.h"
      15             : #include "mozilla/dom/PushSubscriptionOptions.h"
      16             : #include "mozilla/dom/PushUtil.h"
      17             : #include "mozilla/dom/WorkerPrivate.h"
      18             : #include "mozilla/dom/WorkerScope.h"
      19             : #include "mozilla/dom/workers/Workers.h"
      20             : 
      21             : namespace mozilla {
      22             : namespace dom {
      23             : 
      24             : using namespace workers;
      25             : 
      26             : namespace {
      27             : 
      28             : class UnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
      29             : {
      30             : public:
      31             :   NS_DECL_ISUPPORTS
      32             : 
      33           0 :   explicit UnsubscribeResultCallback(Promise* aPromise)
      34           0 :     : mPromise(aPromise)
      35             :   {
      36           0 :     AssertIsOnMainThread();
      37           0 :   }
      38             : 
      39             :   NS_IMETHOD
      40           0 :   OnUnsubscribe(nsresult aStatus, bool aSuccess) override
      41             :   {
      42           0 :     if (NS_SUCCEEDED(aStatus)) {
      43           0 :       mPromise->MaybeResolve(aSuccess);
      44             :     } else {
      45           0 :       mPromise->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
      46             :     }
      47             : 
      48           0 :     return NS_OK;
      49             :   }
      50             : 
      51             : private:
      52           0 :   ~UnsubscribeResultCallback()
      53           0 :   {}
      54             : 
      55             :   RefPtr<Promise> mPromise;
      56             : };
      57             : 
      58           0 : NS_IMPL_ISUPPORTS(UnsubscribeResultCallback, nsIUnsubscribeResultCallback)
      59             : 
      60             : class UnsubscribeResultRunnable final : public WorkerRunnable
      61             : {
      62             : public:
      63           0 :   UnsubscribeResultRunnable(WorkerPrivate* aWorkerPrivate,
      64             :                             already_AddRefed<PromiseWorkerProxy>&& aProxy,
      65             :                             nsresult aStatus,
      66             :                             bool aSuccess)
      67           0 :     : WorkerRunnable(aWorkerPrivate)
      68           0 :     , mProxy(Move(aProxy))
      69             :     , mStatus(aStatus)
      70           0 :     , mSuccess(aSuccess)
      71             :   {
      72           0 :     AssertIsOnMainThread();
      73           0 :   }
      74             : 
      75             :   bool
      76           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
      77             :   {
      78           0 :     MOZ_ASSERT(aWorkerPrivate);
      79           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
      80             : 
      81           0 :     RefPtr<Promise> promise = mProxy->WorkerPromise();
      82           0 :     if (NS_SUCCEEDED(mStatus)) {
      83           0 :       promise->MaybeResolve(mSuccess);
      84             :     } else {
      85           0 :       promise->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
      86             :     }
      87             : 
      88           0 :     mProxy->CleanUp();
      89             : 
      90           0 :     return true;
      91             :   }
      92             : private:
      93           0 :   ~UnsubscribeResultRunnable()
      94           0 :   {}
      95             : 
      96             :   RefPtr<PromiseWorkerProxy> mProxy;
      97             :   nsresult mStatus;
      98             :   bool mSuccess;
      99             : };
     100             : 
     101             : class WorkerUnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
     102             : {
     103             : public:
     104             :   NS_DECL_ISUPPORTS
     105             : 
     106           0 :   explicit WorkerUnsubscribeResultCallback(PromiseWorkerProxy* aProxy)
     107           0 :     : mProxy(aProxy)
     108             :   {
     109           0 :     AssertIsOnMainThread();
     110           0 :   }
     111             : 
     112             :   NS_IMETHOD
     113           0 :   OnUnsubscribe(nsresult aStatus, bool aSuccess) override
     114             :   {
     115           0 :     AssertIsOnMainThread();
     116           0 :     MOZ_ASSERT(mProxy, "OnUnsubscribe() called twice?");
     117             : 
     118           0 :     MutexAutoLock lock(mProxy->Lock());
     119           0 :     if (mProxy->CleanedUp()) {
     120           0 :       return NS_OK;
     121             :     }
     122             : 
     123           0 :     WorkerPrivate* worker = mProxy->GetWorkerPrivate();
     124             :     RefPtr<UnsubscribeResultRunnable> r =
     125           0 :       new UnsubscribeResultRunnable(worker, mProxy.forget(), aStatus, aSuccess);
     126           0 :     MOZ_ALWAYS_TRUE(r->Dispatch());
     127             : 
     128           0 :     return NS_OK;
     129             :   }
     130             : 
     131             : private:
     132           0 :   ~WorkerUnsubscribeResultCallback()
     133           0 :   {
     134           0 :   }
     135             : 
     136             :   RefPtr<PromiseWorkerProxy> mProxy;
     137             : };
     138             : 
     139           0 : NS_IMPL_ISUPPORTS(WorkerUnsubscribeResultCallback, nsIUnsubscribeResultCallback)
     140             : 
     141             : class UnsubscribeRunnable final : public Runnable
     142             : {
     143             : public:
     144           0 :   UnsubscribeRunnable(PromiseWorkerProxy* aProxy, const nsAString& aScope)
     145           0 :     : Runnable("dom::UnsubscribeRunnable")
     146             :     , mProxy(aProxy)
     147           0 :     , mScope(aScope)
     148             :   {
     149           0 :     MOZ_ASSERT(aProxy);
     150           0 :     MOZ_ASSERT(!aScope.IsEmpty());
     151           0 :   }
     152             : 
     153             :   NS_IMETHOD
     154           0 :   Run() override
     155             :   {
     156           0 :     AssertIsOnMainThread();
     157             : 
     158           0 :     nsCOMPtr<nsIPrincipal> principal;
     159             : 
     160             :     {
     161           0 :       MutexAutoLock lock(mProxy->Lock());
     162           0 :       if (mProxy->CleanedUp()) {
     163           0 :         return NS_OK;
     164             :       }
     165           0 :       principal = mProxy->GetWorkerPrivate()->GetPrincipal();
     166             :     }
     167             : 
     168           0 :     MOZ_ASSERT(principal);
     169             : 
     170             :     RefPtr<WorkerUnsubscribeResultCallback> callback =
     171           0 :       new WorkerUnsubscribeResultCallback(mProxy);
     172             : 
     173             :     nsCOMPtr<nsIPushService> service =
     174           0 :       do_GetService("@mozilla.org/push/Service;1");
     175           0 :     if (NS_WARN_IF(!service)) {
     176           0 :       callback->OnUnsubscribe(NS_ERROR_FAILURE, false);
     177           0 :       return NS_OK;
     178             :     }
     179             : 
     180           0 :     if (NS_WARN_IF(NS_FAILED(service->Unsubscribe(mScope, principal, callback)))) {
     181           0 :       callback->OnUnsubscribe(NS_ERROR_FAILURE, false);
     182           0 :       return NS_OK;
     183             :     }
     184             : 
     185           0 :     return NS_OK;
     186             :   }
     187             : 
     188             : private:
     189           0 :   ~UnsubscribeRunnable()
     190           0 :   {}
     191             : 
     192             :   RefPtr<PromiseWorkerProxy> mProxy;
     193             :   nsString mScope;
     194             : };
     195             : 
     196             : } // anonymous namespace
     197             : 
     198           0 : PushSubscription::PushSubscription(nsIGlobalObject* aGlobal,
     199             :                                    const nsAString& aEndpoint,
     200             :                                    const nsAString& aScope,
     201             :                                    nsTArray<uint8_t>&& aRawP256dhKey,
     202             :                                    nsTArray<uint8_t>&& aAuthSecret,
     203           0 :                                    nsTArray<uint8_t>&& aAppServerKey)
     204             :   : mEndpoint(aEndpoint)
     205             :   , mScope(aScope)
     206           0 :   , mRawP256dhKey(Move(aRawP256dhKey))
     207           0 :   , mAuthSecret(Move(aAuthSecret))
     208             : {
     209           0 :   if (NS_IsMainThread()) {
     210           0 :     mGlobal = aGlobal;
     211             :   } else {
     212             : #ifdef DEBUG
     213             :     // There's only one global on a worker, so we don't need to pass a global
     214             :     // object to the constructor.
     215           0 :     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     216           0 :     MOZ_ASSERT(worker);
     217           0 :     worker->AssertIsOnWorkerThread();
     218             : #endif
     219             :   }
     220           0 :   mOptions = new PushSubscriptionOptions(mGlobal, Move(aAppServerKey));
     221           0 : }
     222             : 
     223           0 : PushSubscription::~PushSubscription()
     224           0 : {}
     225             : 
     226           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushSubscription, mGlobal, mOptions)
     227           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(PushSubscription)
     228           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(PushSubscription)
     229           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushSubscription)
     230           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     231           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     232           0 : NS_INTERFACE_MAP_END
     233             : 
     234             : JSObject*
     235           0 : PushSubscription::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     236             : {
     237           0 :   return PushSubscriptionBinding::Wrap(aCx, this, aGivenProto);
     238             : }
     239             : 
     240             : // static
     241             : already_AddRefed<PushSubscription>
     242           0 : PushSubscription::Constructor(GlobalObject& aGlobal,
     243             :                               const PushSubscriptionInit& aInitDict,
     244             :                               ErrorResult& aRv)
     245             : {
     246           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
     247             : 
     248           0 :   nsTArray<uint8_t> rawKey;
     249           0 :   if (aInitDict.mP256dhKey.WasPassed() &&
     250           0 :       !aInitDict.mP256dhKey.Value().IsNull() &&
     251           0 :       !PushUtil::CopyArrayBufferToArray(aInitDict.mP256dhKey.Value().Value(),
     252             :                                         rawKey)) {
     253           0 :     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     254           0 :     return nullptr;
     255             :   }
     256             : 
     257           0 :   nsTArray<uint8_t> authSecret;
     258           0 :   if (aInitDict.mAuthSecret.WasPassed() &&
     259           0 :       !aInitDict.mAuthSecret.Value().IsNull() &&
     260           0 :       !PushUtil::CopyArrayBufferToArray(aInitDict.mAuthSecret.Value().Value(),
     261             :                                         authSecret)) {
     262           0 :     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     263           0 :     return nullptr;
     264             :   }
     265             : 
     266           0 :   nsTArray<uint8_t> appServerKey;
     267           0 :   if (aInitDict.mAppServerKey.WasPassed() &&
     268           0 :       !aInitDict.mAppServerKey.Value().IsNull()) {
     269             :     const OwningArrayBufferViewOrArrayBuffer& bufferSource =
     270           0 :       aInitDict.mAppServerKey.Value().Value();
     271           0 :     if (!PushUtil::CopyBufferSourceToArray(bufferSource, appServerKey)) {
     272           0 :       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     273           0 :       return nullptr;
     274             :     }
     275             :   }
     276             : 
     277             :   RefPtr<PushSubscription> sub = new PushSubscription(global,
     278             :                                                       aInitDict.mEndpoint,
     279             :                                                       aInitDict.mScope,
     280             :                                                       Move(rawKey),
     281             :                                                       Move(authSecret),
     282           0 :                                                       Move(appServerKey));
     283             : 
     284           0 :   return sub.forget();
     285             : }
     286             : 
     287             : already_AddRefed<Promise>
     288           0 : PushSubscription::Unsubscribe(ErrorResult& aRv)
     289             : {
     290           0 :   if (!NS_IsMainThread()) {
     291           0 :     RefPtr<Promise> p = UnsubscribeFromWorker(aRv);
     292           0 :     return p.forget();
     293             :   }
     294             : 
     295           0 :   MOZ_ASSERT(mGlobal);
     296             : 
     297             :   nsCOMPtr<nsIPushService> service =
     298           0 :     do_GetService("@mozilla.org/push/Service;1");
     299           0 :   if (NS_WARN_IF(!service)) {
     300           0 :     aRv.Throw(NS_ERROR_FAILURE);
     301           0 :     return nullptr;
     302             :   }
     303             : 
     304           0 :   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mGlobal);
     305           0 :   if (!sop) {
     306           0 :     aRv.Throw(NS_ERROR_FAILURE);
     307           0 :     return nullptr;
     308             :   }
     309             : 
     310           0 :   RefPtr<Promise> p = Promise::Create(mGlobal, aRv);
     311           0 :   if (NS_WARN_IF(aRv.Failed())) {
     312           0 :     return nullptr;
     313             :   }
     314             : 
     315             :   RefPtr<UnsubscribeResultCallback> callback =
     316           0 :     new UnsubscribeResultCallback(p);
     317           0 :   Unused << NS_WARN_IF(NS_FAILED(
     318             :     service->Unsubscribe(mScope, sop->GetPrincipal(), callback)));
     319             : 
     320           0 :   return p.forget();
     321             : }
     322             : 
     323             : void
     324           0 : PushSubscription::GetKey(JSContext* aCx,
     325             :                          PushEncryptionKeyName aType,
     326             :                          JS::MutableHandle<JSObject*> aKey,
     327             :                          ErrorResult& aRv)
     328             : {
     329           0 :   if (aType == PushEncryptionKeyName::P256dh) {
     330           0 :     PushUtil::CopyArrayToArrayBuffer(aCx, mRawP256dhKey, aKey, aRv);
     331           0 :   } else if (aType == PushEncryptionKeyName::Auth) {
     332           0 :     PushUtil::CopyArrayToArrayBuffer(aCx, mAuthSecret, aKey, aRv);
     333             :   } else {
     334           0 :     aKey.set(nullptr);
     335             :   }
     336           0 : }
     337             : 
     338             : void
     339           0 : PushSubscription::ToJSON(PushSubscriptionJSON& aJSON, ErrorResult& aRv)
     340             : {
     341           0 :   aJSON.mEndpoint.Construct();
     342           0 :   aJSON.mEndpoint.Value() = mEndpoint;
     343             : 
     344           0 :   aJSON.mKeys.mP256dh.Construct();
     345           0 :   nsresult rv = Base64URLEncode(mRawP256dhKey.Length(),
     346           0 :                                 mRawP256dhKey.Elements(),
     347             :                                 Base64URLEncodePaddingPolicy::Omit,
     348           0 :                                 aJSON.mKeys.mP256dh.Value());
     349           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     350           0 :     aRv.Throw(rv);
     351           0 :     return;
     352             :   }
     353             : 
     354           0 :   aJSON.mKeys.mAuth.Construct();
     355           0 :   rv = Base64URLEncode(mAuthSecret.Length(), mAuthSecret.Elements(),
     356             :                        Base64URLEncodePaddingPolicy::Omit,
     357           0 :                        aJSON.mKeys.mAuth.Value());
     358           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     359           0 :     aRv.Throw(rv);
     360           0 :     return;
     361             :   }
     362             : }
     363             : 
     364             : already_AddRefed<PushSubscriptionOptions>
     365           0 : PushSubscription::Options()
     366             : {
     367           0 :   RefPtr<PushSubscriptionOptions> options = mOptions;
     368           0 :   return options.forget();
     369             : }
     370             : 
     371             : already_AddRefed<Promise>
     372           0 : PushSubscription::UnsubscribeFromWorker(ErrorResult& aRv)
     373             : {
     374           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     375           0 :   MOZ_ASSERT(worker);
     376           0 :   worker->AssertIsOnWorkerThread();
     377             : 
     378           0 :   nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
     379           0 :   RefPtr<Promise> p = Promise::Create(global, aRv);
     380           0 :   if (NS_WARN_IF(aRv.Failed())) {
     381           0 :     return nullptr;
     382             :   }
     383             : 
     384           0 :   RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
     385           0 :   if (!proxy) {
     386           0 :     p->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
     387           0 :     return p.forget();
     388             :   }
     389             : 
     390             :   RefPtr<UnsubscribeRunnable> r =
     391           0 :     new UnsubscribeRunnable(proxy, mScope);
     392           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
     393             : 
     394           0 :   return p.forget();
     395             : }
     396             : 
     397             : } // namespace dom
     398             : } // namespace mozilla

Generated by: LCOV version 1.13