LCOV - code coverage report
Current view: top level - dom/fetch - FetchConsumer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 142 303 46.9 %
Date: 2017-07-14 16:53:18 Functions: 27 102 26.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "Fetch.h"
       8             : #include "FetchConsumer.h"
       9             : 
      10             : #include "nsIInputStreamPump.h"
      11             : #include "nsProxyRelease.h"
      12             : #include "WorkerPrivate.h"
      13             : #include "WorkerRunnable.h"
      14             : #include "WorkerScope.h"
      15             : #include "Workers.h"
      16             : 
      17             : namespace mozilla {
      18             : namespace dom {
      19             : 
      20             : using namespace workers;
      21             : 
      22             : namespace {
      23             : 
      24             : template <class Derived>
      25             : class FetchBodyWorkerHolder final : public workers::WorkerHolder
      26             : {
      27             :   RefPtr<FetchBodyConsumer<Derived>> mConsumer;
      28             :   bool mWasNotified;
      29             : 
      30             : public:
      31           0 :   explicit FetchBodyWorkerHolder(FetchBodyConsumer<Derived>* aConsumer)
      32             :     : mConsumer(aConsumer)
      33           0 :     , mWasNotified(false)
      34             :   {
      35           0 :     MOZ_ASSERT(aConsumer);
      36           0 :   }
      37             : 
      38           0 :   ~FetchBodyWorkerHolder() = default;
      39             : 
      40           0 :   bool Notify(workers::Status aStatus) override
      41             :   {
      42           0 :     MOZ_ASSERT(aStatus > workers::Running);
      43           0 :     if (!mWasNotified) {
      44           0 :       mWasNotified = true;
      45             :       // This will probably cause the releasing of the consumer.
      46             :       // The WorkerHolder will be released as well.
      47           0 :       mConsumer->ContinueConsumeBody(NS_BINDING_ABORTED, 0, nullptr);
      48             :     }
      49             : 
      50           0 :     return true;
      51             :   }
      52             : };
      53             : 
      54             : template <class Derived>
      55           3 : class BeginConsumeBodyRunnable final : public Runnable
      56             : {
      57             :   RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
      58             : 
      59             : public:
      60           1 :   explicit BeginConsumeBodyRunnable(FetchBodyConsumer<Derived>* aConsumer)
      61             :     : Runnable("BeginConsumeBodyRunnable")
      62           1 :     , mFetchBodyConsumer(aConsumer)
      63           1 :   { }
      64             : 
      65             :   NS_IMETHOD
      66           1 :   Run() override
      67             :   {
      68           1 :     mFetchBodyConsumer->BeginConsumeBodyMainThread();
      69           1 :     return NS_OK;
      70             :   }
      71             : };
      72             : 
      73             : /*
      74             :  * Called on successfully reading the complete stream.
      75             :  */
      76             : template <class Derived>
      77           0 : class ContinueConsumeBodyRunnable final : public MainThreadWorkerRunnable
      78             : {
      79             :   RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
      80             :   nsresult mStatus;
      81             :   uint32_t mLength;
      82             :   uint8_t* mResult;
      83             : 
      84             : public:
      85           0 :   ContinueConsumeBodyRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer,
      86             :                               nsresult aStatus, uint32_t aLength,
      87             :                               uint8_t* aResult)
      88             :     : MainThreadWorkerRunnable(aFetchBodyConsumer->GetWorkerPrivate())
      89             :     , mFetchBodyConsumer(aFetchBodyConsumer)
      90             :     , mStatus(aStatus)
      91             :     , mLength(aLength)
      92           0 :     , mResult(aResult)
      93             :   {
      94           0 :     MOZ_ASSERT(NS_IsMainThread());
      95           0 :   }
      96             : 
      97             :   bool
      98           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
      99             :   {
     100           0 :     mFetchBodyConsumer->ContinueConsumeBody(mStatus, mLength, mResult);
     101           0 :     return true;
     102             :   }
     103             : };
     104             : 
     105             : template <class Derived>
     106           0 : class FailConsumeBodyWorkerRunnable : public MainThreadWorkerControlRunnable
     107             : {
     108             :   RefPtr<FetchBodyConsumer<Derived>> mBodyConsumer;
     109             : 
     110             : public:
     111           0 :   explicit FailConsumeBodyWorkerRunnable(FetchBodyConsumer<Derived>* aBodyConsumer)
     112             :     : MainThreadWorkerControlRunnable(aBodyConsumer->GetWorkerPrivate())
     113           0 :     , mBodyConsumer(aBodyConsumer)
     114             :   {
     115           0 :     AssertIsOnMainThread();
     116           0 :   }
     117             : 
     118             :   bool
     119           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     120             :   {
     121           0 :     mBodyConsumer->ContinueConsumeBody(NS_ERROR_FAILURE, 0, nullptr);
     122           0 :     return true;
     123             :   }
     124             : };
     125             : 
     126             : /*
     127             :  * In case of failure to create a stream pump or dispatch stream completion to
     128             :  * worker, ensure we cleanup properly. Thread agnostic.
     129             :  */
     130             : template <class Derived>
     131             : class MOZ_STACK_CLASS AutoFailConsumeBody final
     132             : {
     133             :   RefPtr<FetchBodyConsumer<Derived>> mBodyConsumer;
     134             : 
     135             : public:
     136           1 :   explicit AutoFailConsumeBody(FetchBodyConsumer<Derived>* aBodyConsumer)
     137           1 :     : mBodyConsumer(aBodyConsumer)
     138           1 :   {}
     139             : 
     140           1 :   ~AutoFailConsumeBody()
     141             :   {
     142           1 :     AssertIsOnMainThread();
     143             : 
     144           1 :     if (mBodyConsumer) {
     145           0 :       if (mBodyConsumer->GetWorkerPrivate()) {
     146             :         RefPtr<FailConsumeBodyWorkerRunnable<Derived>> r =
     147           0 :           new FailConsumeBodyWorkerRunnable<Derived>(mBodyConsumer);
     148           0 :         if (!r->Dispatch()) {
     149           0 :           MOZ_CRASH("We are going to leak");
     150             :         }
     151             :       } else {
     152           0 :         mBodyConsumer->ContinueConsumeBody(NS_ERROR_FAILURE, 0, nullptr);
     153             :       }
     154             :     }
     155           1 :   }
     156             : 
     157             :   void
     158           1 :   DontFail()
     159             :   {
     160           1 :     mBodyConsumer = nullptr;
     161           1 :   }
     162             : };
     163             : 
     164             : /*
     165             :  * Called on successfully reading the complete stream for Blob.
     166             :  */
     167             : template <class Derived>
     168           0 : class ContinueConsumeBlobBodyRunnable final : public MainThreadWorkerRunnable
     169             : {
     170             :   RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
     171             :   RefPtr<BlobImpl> mBlobImpl;
     172             : 
     173             : public:
     174           0 :   ContinueConsumeBlobBodyRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer,
     175             :                                   BlobImpl* aBlobImpl)
     176             :     : MainThreadWorkerRunnable(aFetchBodyConsumer->GetWorkerPrivate())
     177             :     , mFetchBodyConsumer(aFetchBodyConsumer)
     178           0 :     , mBlobImpl(aBlobImpl)
     179             :   {
     180           0 :     MOZ_ASSERT(NS_IsMainThread());
     181           0 :     MOZ_ASSERT(mBlobImpl);
     182           0 :   }
     183             : 
     184             :   bool
     185           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     186             :   {
     187           0 :     mFetchBodyConsumer->ContinueConsumeBlobBody(mBlobImpl);
     188           0 :     return true;
     189             :   }
     190             : };
     191             : 
     192             : template <class Derived>
     193             : class ConsumeBodyDoneObserver : public nsIStreamLoaderObserver
     194             :                               , public MutableBlobStorageCallback
     195             : {
     196             :   RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
     197             : 
     198             : public:
     199             :   NS_DECL_THREADSAFE_ISUPPORTS
     200             : 
     201           1 :   explicit ConsumeBodyDoneObserver(FetchBodyConsumer<Derived>* aFetchBodyConsumer)
     202           1 :     : mFetchBodyConsumer(aFetchBodyConsumer)
     203           1 :   { }
     204             : 
     205             :   NS_IMETHOD
     206           1 :   OnStreamComplete(nsIStreamLoader* aLoader,
     207             :                    nsISupports* aCtxt,
     208             :                    nsresult aStatus,
     209             :                    uint32_t aResultLength,
     210             :                    const uint8_t* aResult) override
     211             :   {
     212           1 :     MOZ_ASSERT(NS_IsMainThread());
     213             : 
     214             :     // The loading is completed. Let's nullify the pump before continuing the
     215             :     // consuming of the body.
     216           1 :     mFetchBodyConsumer->NullifyConsumeBodyPump();
     217             : 
     218             :     // If the binding requested cancel, we don't need to call
     219             :     // ContinueConsumeBody, since that is the originator.
     220           1 :     if (aStatus == NS_BINDING_ABORTED) {
     221           0 :       return NS_OK;
     222             :     }
     223             : 
     224           1 :     uint8_t* nonconstResult = const_cast<uint8_t*>(aResult);
     225           1 :     if (mFetchBodyConsumer->GetWorkerPrivate()) {
     226             :       RefPtr<ContinueConsumeBodyRunnable<Derived>> r =
     227           0 :         new ContinueConsumeBodyRunnable<Derived>(mFetchBodyConsumer,
     228             :                                                  aStatus,
     229             :                                                  aResultLength,
     230           0 :                                                  nonconstResult);
     231           0 :       if (!r->Dispatch()) {
     232           0 :         NS_WARNING("Could not dispatch ConsumeBodyRunnable");
     233             :         // Return failure so that aResult is freed.
     234           0 :         return NS_ERROR_FAILURE;
     235             :       }
     236             :     } else {
     237           1 :       mFetchBodyConsumer->ContinueConsumeBody(aStatus, aResultLength,
     238             :                                               nonconstResult);
     239             :     }
     240             : 
     241             :     // FetchBody is responsible for data.
     242           1 :     return NS_SUCCESS_ADOPTED_DATA;
     243             :   }
     244             : 
     245           0 :   virtual void BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
     246             :                                   Blob* aBlob,
     247             :                                   nsresult aRv) override
     248             :   {
     249             :     // On error.
     250           0 :     if (NS_FAILED(aRv)) {
     251           0 :       OnStreamComplete(nullptr, nullptr, aRv, 0, nullptr);
     252           0 :       return;
     253             :     }
     254             : 
     255           0 :     MOZ_ASSERT(aBlob);
     256             : 
     257           0 :     if (mFetchBodyConsumer->GetWorkerPrivate()) {
     258             :       RefPtr<ContinueConsumeBlobBodyRunnable<Derived>> r =
     259           0 :         new ContinueConsumeBlobBodyRunnable<Derived>(mFetchBodyConsumer,
     260           0 :                                                      aBlob->Impl());
     261             : 
     262           0 :       if (!r->Dispatch()) {
     263           0 :         NS_WARNING("Could not dispatch ConsumeBlobBodyRunnable");
     264           0 :         return;
     265             :       }
     266             :     } else {
     267           0 :       mFetchBodyConsumer->ContinueConsumeBlobBody(aBlob->Impl());
     268             :     }
     269             :   }
     270             : 
     271             : private:
     272           2 :   virtual ~ConsumeBodyDoneObserver()
     273           3 :   { }
     274             : };
     275             : 
     276             : template <class Derived>
     277           3 : NS_IMPL_ADDREF(ConsumeBodyDoneObserver<Derived>)
     278             : template <class Derived>
     279           3 : NS_IMPL_RELEASE(ConsumeBodyDoneObserver<Derived>)
     280             : template <class Derived>
     281           1 : NS_INTERFACE_MAP_BEGIN(ConsumeBodyDoneObserver<Derived>)
     282           1 :   NS_INTERFACE_MAP_ENTRY(nsIStreamLoaderObserver)
     283           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamLoaderObserver)
     284           0 : NS_INTERFACE_MAP_END
     285             : 
     286             : template <class Derived>
     287           0 : class ShutDownMainThreadConsumingRunnable final : public WorkerMainThreadRunnable
     288             : {
     289             :   RefPtr<FetchBodyConsumer<Derived>> mBodyConsumer;
     290             : 
     291             : public:
     292           0 :   explicit ShutDownMainThreadConsumingRunnable(FetchBodyConsumer<Derived>* aBodyConsumer)
     293             :     : WorkerMainThreadRunnable(aBodyConsumer->GetWorkerPrivate(),
     294             :                                NS_LITERAL_CSTRING("Fetch :: Cancel Pump"))
     295           0 :     , mBodyConsumer(aBodyConsumer)
     296           0 :   {}
     297             : 
     298             :   bool
     299           0 :   MainThreadRun() override
     300             :   {
     301           0 :     mBodyConsumer->ShutDownMainThreadConsuming();
     302           0 :     return true;
     303             :   }
     304             : };
     305             : 
     306             : } // anonymous
     307             : 
     308             : template <class Derived>
     309             : /* static */ already_AddRefed<Promise>
     310           1 : FetchBodyConsumer<Derived>::Create(nsIGlobalObject* aGlobal,
     311             :                                    nsIEventTarget* aMainThreadEventTarget,
     312             :                                    FetchBody<Derived>* aBody,
     313             :                                    FetchConsumeType aType,
     314             :                                    ErrorResult& aRv)
     315             : {
     316           1 :   MOZ_ASSERT(aBody);
     317           1 :   MOZ_ASSERT(aMainThreadEventTarget);
     318             : 
     319           2 :   RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
     320           1 :   if (aRv.Failed()) {
     321           0 :     return nullptr;
     322             :   }
     323             : 
     324           1 :   WorkerPrivate* workerPrivate = nullptr;
     325           1 :   if (!NS_IsMainThread()) {
     326           0 :     workerPrivate = GetCurrentThreadWorkerPrivate();
     327           0 :     MOZ_ASSERT(workerPrivate);
     328             :   }
     329             : 
     330             :   RefPtr<FetchBodyConsumer<Derived>> consumer =
     331           2 :     new FetchBodyConsumer<Derived>(aMainThreadEventTarget, aGlobal,
     332           2 :                                    workerPrivate, aBody, promise, aType);
     333             : 
     334           1 :   if (!NS_IsMainThread()) {
     335           0 :     MOZ_ASSERT(workerPrivate);
     336           0 :     if (NS_WARN_IF(!consumer->RegisterWorkerHolder(workerPrivate))) {
     337           0 :       aRv.Throw(NS_ERROR_FAILURE);
     338           0 :       return nullptr;
     339             :     }
     340             :   } else {
     341           2 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     342           1 :     if (NS_WARN_IF(!os)) {
     343           0 :       aRv.Throw(NS_ERROR_FAILURE);
     344           0 :       return nullptr;
     345             :     }
     346             : 
     347           1 :     aRv = os->AddObserver(consumer, DOM_WINDOW_DESTROYED_TOPIC, true);
     348           1 :     if (NS_WARN_IF(aRv.Failed())) {
     349           0 :       return nullptr;
     350             :     }
     351             : 
     352           1 :     aRv = os->AddObserver(consumer, DOM_WINDOW_FROZEN_TOPIC, true);
     353           1 :     if (NS_WARN_IF(aRv.Failed())) {
     354           0 :       return nullptr;
     355             :     }
     356             :   }
     357             : 
     358           3 :   nsCOMPtr<nsIRunnable> r = new BeginConsumeBodyRunnable<Derived>(consumer);
     359           1 :   aRv = aMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
     360           1 :   if (NS_WARN_IF(aRv.Failed())) {
     361           0 :     return nullptr;
     362             :   }
     363             : 
     364           1 :   return promise.forget();
     365             : }
     366             : 
     367             : template <class Derived>
     368             : void
     369           1 : FetchBodyConsumer<Derived>::ReleaseObject()
     370             : {
     371           1 :   AssertIsOnTargetThread();
     372             : 
     373           1 :   if (NS_IsMainThread()) {
     374           2 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     375           1 :     if (os) {
     376           1 :       os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
     377           1 :       os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
     378             :     }
     379             :   }
     380             : 
     381           1 :   mGlobal = nullptr;
     382           1 :   mWorkerHolder = nullptr;
     383           1 :   mBody = nullptr;
     384           1 : }
     385             : 
     386             : template <class Derived>
     387           1 : FetchBodyConsumer<Derived>::FetchBodyConsumer(nsIEventTarget* aMainThreadEventTarget,
     388             :                                               nsIGlobalObject* aGlobalObject,
     389             :                                               WorkerPrivate* aWorkerPrivate,
     390             :                                               FetchBody<Derived>* aBody,
     391             :                                               Promise* aPromise,
     392             :                                               FetchConsumeType aType)
     393             :   : mTargetThread(NS_GetCurrentThread())
     394             :   , mMainThreadEventTarget(aMainThreadEventTarget)
     395             :   , mBody(aBody)
     396             :   , mGlobal(aGlobalObject)
     397             :   , mWorkerPrivate(aWorkerPrivate)
     398             :   , mConsumeType(aType)
     399             :   , mConsumePromise(aPromise)
     400             :   , mBodyConsumed(false)
     401           1 :   , mShuttingDown(false)
     402             : {
     403           1 :   MOZ_ASSERT(aMainThreadEventTarget);
     404           1 :   MOZ_ASSERT(aBody);
     405           1 :   MOZ_ASSERT(aPromise);
     406           1 : }
     407             : 
     408             : template <class Derived>
     409           1 : FetchBodyConsumer<Derived>::~FetchBodyConsumer()
     410             : {
     411           1 : }
     412             : 
     413             : template <class Derived>
     414             : void
     415           2 : FetchBodyConsumer<Derived>::AssertIsOnTargetThread() const
     416             : {
     417           2 :   MOZ_ASSERT(NS_GetCurrentThread() == mTargetThread);
     418           2 : }
     419             : 
     420             : template <class Derived>
     421             : bool
     422           0 : FetchBodyConsumer<Derived>::RegisterWorkerHolder(WorkerPrivate* aWorkerPrivate)
     423             : {
     424           0 :   MOZ_ASSERT(aWorkerPrivate);
     425           0 :   aWorkerPrivate->AssertIsOnWorkerThread();
     426             : 
     427           0 :   MOZ_ASSERT(!mWorkerHolder);
     428           0 :   mWorkerHolder.reset(new FetchBodyWorkerHolder<Derived>(this));
     429             : 
     430           0 :   if (!mWorkerHolder->HoldWorker(aWorkerPrivate, Closing)) {
     431           0 :     NS_WARNING("Failed to add workerHolder");
     432           0 :     mWorkerHolder = nullptr;
     433           0 :     return false;
     434             :   }
     435             : 
     436           0 :   return true;
     437             : }
     438             : 
     439             : /*
     440             :  * BeginConsumeBodyMainThread() will automatically reject the consume promise
     441             :  * and clean up on any failures, so there is no need for callers to do so,
     442             :  * reflected in a lack of error return code.
     443             :  */
     444             : template <class Derived>
     445             : void
     446           1 : FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread()
     447             : {
     448           1 :   AssertIsOnMainThread();
     449             : 
     450             :   // Nothing to do.
     451           1 :   if (mShuttingDown) {
     452           0 :     return;
     453             :   }
     454             : 
     455           2 :   AutoFailConsumeBody<Derived> autoReject(this);
     456             : 
     457             :   nsresult rv;
     458           2 :   nsCOMPtr<nsIInputStream> stream;
     459           1 :   mBody->DerivedClass()->GetBody(getter_AddRefs(stream));
     460           1 :   if (!stream) {
     461           0 :     rv = NS_NewCStringInputStream(getter_AddRefs(stream), EmptyCString());
     462           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     463           0 :       return;
     464             :     }
     465             :   }
     466             : 
     467           2 :   nsCOMPtr<nsIInputStreamPump> pump;
     468           1 :   rv = NS_NewInputStreamPump(getter_AddRefs(pump),
     469             :                              stream, -1, -1, 0, 0, false,
     470             :                              mMainThreadEventTarget);
     471           1 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     472           0 :     return;
     473             :   }
     474             : 
     475             :   RefPtr<ConsumeBodyDoneObserver<Derived>> p =
     476           2 :    new ConsumeBodyDoneObserver<Derived>(this);
     477             : 
     478           2 :   nsCOMPtr<nsIStreamListener> listener;
     479           1 :   if (mConsumeType == CONSUME_BLOB) {
     480             :     MutableBlobStorage::MutableBlobStorageType type =
     481           0 :       MutableBlobStorage::eOnlyInMemory;
     482             : 
     483             :     const mozilla::UniquePtr<mozilla::ipc::PrincipalInfo>& principalInfo =
     484           0 :       mBody->DerivedClass()->GetPrincipalInfo();
     485             :     // We support temporary file for blobs only if the principal is known and
     486             :     // it's system or content not in private Browsing.
     487           0 :     if (principalInfo &&
     488           0 :         (principalInfo->type() == mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo ||
     489           0 :          (principalInfo->type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo &&
     490           0 :           principalInfo->get_ContentPrincipalInfo().attrs().mPrivateBrowsingId == 0))) {
     491           0 :       type = MutableBlobStorage::eCouldBeInTemporaryFile;
     492             :     }
     493             : 
     494           0 :     listener = new MutableBlobStreamListener(type, nullptr, mBody->MimeType(),
     495             :                                              p, mMainThreadEventTarget);
     496             :   } else {
     497           2 :     nsCOMPtr<nsIStreamLoader> loader;
     498           1 :     rv = NS_NewStreamLoader(getter_AddRefs(loader), p);
     499           1 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     500           0 :       return;
     501             :     }
     502             : 
     503           1 :     listener = loader;
     504             :   }
     505             : 
     506           1 :   rv = pump->AsyncRead(listener, nullptr);
     507           1 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     508           0 :     return;
     509             :   }
     510             : 
     511             :   // Now that everything succeeded, we can assign the pump to a pointer that
     512             :   // stays alive for the lifetime of the FetchConsumer.
     513           1 :   mConsumeBodyPump = pump;
     514             : 
     515             :   // It is ok for retargeting to fail and reads to happen on the main thread.
     516           1 :   autoReject.DontFail();
     517             : 
     518             :   // Try to retarget, otherwise fall back to main thread.
     519           2 :   nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(pump);
     520           1 :   if (rr) {
     521           2 :     nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
     522           1 :     rv = rr->RetargetDeliveryTo(sts);
     523           1 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     524           0 :       NS_WARNING("Retargeting failed");
     525             :     }
     526             :   }
     527             : }
     528             : 
     529             : template <class Derived>
     530             : void
     531           1 : FetchBodyConsumer<Derived>::ContinueConsumeBody(nsresult aStatus,
     532             :                                                 uint32_t aResultLength,
     533             :                                                 uint8_t* aResult)
     534             : {
     535           1 :   AssertIsOnTargetThread();
     536             : 
     537           1 :   if (mBodyConsumed) {
     538           0 :     return;
     539             :   }
     540           1 :   mBodyConsumed = true;
     541             : 
     542             :   // Just a precaution to ensure ContinueConsumeBody is not called out of
     543             :   // sync with a body read.
     544           1 :   MOZ_ASSERT(mBody->BodyUsed());
     545             : 
     546           1 :   auto autoFree = mozilla::MakeScopeExit([&] {
     547           1 :     free(aResult);
     548           3 :   });
     549             : 
     550           1 :   MOZ_ASSERT(mConsumePromise);
     551           2 :   RefPtr<Promise> localPromise = mConsumePromise.forget();
     552             : 
     553           2 :   RefPtr<FetchBodyConsumer<Derived>> self = this;
     554           1 :   auto autoReleaseObject = mozilla::MakeScopeExit([&] {
     555           1 :     self->ReleaseObject();
     556           3 :   });
     557             : 
     558           1 :   if (NS_WARN_IF(NS_FAILED(aStatus))) {
     559           0 :     localPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     560             :   }
     561             : 
     562             :   // We need to nullify mConsumeBodyPump on the main-thread and, in case it has
     563             :   // not been created yet, we need to block the creation setting mShuttingDown
     564             :   // to true.
     565           1 :   ShutDownMainThreadConsuming();
     566             : 
     567             :   // Don't warn here since we warned above.
     568           1 :   if (NS_FAILED(aStatus)) {
     569           0 :     return;
     570             :   }
     571             : 
     572             :   // Finish successfully consuming body according to type.
     573           1 :   MOZ_ASSERT(aResult);
     574             : 
     575           2 :   AutoJSAPI jsapi;
     576           1 :   if (!jsapi.Init(mBody->DerivedClass()->GetParentObject())) {
     577           0 :     localPromise->MaybeReject(NS_ERROR_UNEXPECTED);
     578           0 :     return;
     579             :   }
     580             : 
     581           1 :   JSContext* cx = jsapi.cx();
     582           2 :   ErrorResult error;
     583             : 
     584           1 :   switch (mConsumeType) {
     585             :     case CONSUME_ARRAYBUFFER: {
     586           0 :       JS::Rooted<JSObject*> arrayBuffer(cx);
     587           0 :       BodyUtil::ConsumeArrayBuffer(cx, &arrayBuffer, aResultLength, aResult,
     588             :                                    error);
     589             : 
     590           0 :       if (!error.Failed()) {
     591           0 :         JS::Rooted<JS::Value> val(cx);
     592           0 :         val.setObjectOrNull(arrayBuffer);
     593             : 
     594           0 :         localPromise->MaybeResolve(cx, val);
     595             :         // ArrayBuffer takes over ownership.
     596           0 :         aResult = nullptr;
     597             :       }
     598           0 :       break;
     599             :     }
     600             :     case CONSUME_BLOB: {
     601           0 :       MOZ_CRASH("This should not happen.");
     602             :       break;
     603             :     }
     604             :     case CONSUME_FORMDATA: {
     605           0 :       nsCString data;
     606           0 :       data.Adopt(reinterpret_cast<char*>(aResult), aResultLength);
     607           0 :       aResult = nullptr;
     608             : 
     609             :       RefPtr<dom::FormData> fd =
     610             :         BodyUtil::ConsumeFormData(mBody->DerivedClass()->GetParentObject(),
     611           0 :                                   mBody->MimeType(), data, error);
     612           0 :       if (!error.Failed()) {
     613           0 :         localPromise->MaybeResolve(fd);
     614             :       }
     615           0 :       break;
     616             :     }
     617             :     case CONSUME_TEXT:
     618             :       // fall through handles early exit.
     619             :     case CONSUME_JSON: {
     620           2 :       nsString decoded;
     621           1 :       if (NS_SUCCEEDED(BodyUtil::ConsumeText(aResultLength, aResult, decoded))) {
     622           1 :         if (mConsumeType == CONSUME_TEXT) {
     623           0 :           localPromise->MaybeResolve(decoded);
     624             :         } else {
     625           2 :           JS::Rooted<JS::Value> json(cx);
     626           1 :           BodyUtil::ConsumeJson(cx, &json, decoded, error);
     627           1 :           if (!error.Failed()) {
     628           1 :             localPromise->MaybeResolve(cx, json);
     629             :           }
     630             :         }
     631             :       };
     632           1 :       break;
     633             :     }
     634             :     default:
     635           0 :       NS_NOTREACHED("Unexpected consume body type");
     636             :   }
     637             : 
     638           1 :   error.WouldReportJSException();
     639           1 :   if (error.Failed()) {
     640           0 :     localPromise->MaybeReject(error);
     641             :   }
     642             : }
     643             : 
     644             : template <class Derived>
     645             : void
     646           0 : FetchBodyConsumer<Derived>::ContinueConsumeBlobBody(BlobImpl* aBlobImpl)
     647             : {
     648           0 :   AssertIsOnTargetThread();
     649           0 :   MOZ_ASSERT(mConsumeType == CONSUME_BLOB);
     650             : 
     651           0 :   if (mBodyConsumed) {
     652           0 :     return;
     653             :   }
     654           0 :   mBodyConsumed = true;
     655             : 
     656             :   // Just a precaution to ensure ContinueConsumeBody is not called out of
     657             :   // sync with a body read.
     658           0 :   MOZ_ASSERT(mBody->BodyUsed());
     659             : 
     660           0 :   MOZ_ASSERT(mConsumePromise);
     661           0 :   RefPtr<Promise> localPromise = mConsumePromise.forget();
     662             : 
     663             :   // Release the pump.
     664           0 :   ShutDownMainThreadConsuming();
     665             : 
     666             :   RefPtr<dom::Blob> blob =
     667           0 :     dom::Blob::Create(mBody->DerivedClass()->GetParentObject(), aBlobImpl);
     668           0 :   MOZ_ASSERT(blob);
     669             : 
     670           0 :   localPromise->MaybeResolve(blob);
     671             : 
     672           0 :   ReleaseObject();
     673             : }
     674             : 
     675             : template <class Derived>
     676             : void
     677           1 : FetchBodyConsumer<Derived>::ShutDownMainThreadConsuming()
     678             : {
     679           1 :   if (!NS_IsMainThread()) {
     680           0 :     MOZ_ASSERT(mWorkerPrivate);
     681             :     // In case of worker thread, we block the worker while the request is
     682             :     // canceled on the main thread. This ensures that OnStreamComplete has a
     683             :     // valid FetchConsumer around to call ShutDownMainThreadConsuming and we
     684             :     // don't release the FetchConsumer on the main thread.
     685             :     RefPtr<ShutDownMainThreadConsumingRunnable<Derived>> r =
     686           0 :       new ShutDownMainThreadConsumingRunnable<Derived>(this);
     687             : 
     688           0 :     IgnoredErrorResult rv;
     689           0 :     r->Dispatch(Killing, rv);
     690           0 :     if (NS_WARN_IF(rv.Failed())) {
     691           0 :       return;
     692             :     }
     693             : 
     694           0 :     MOZ_DIAGNOSTIC_ASSERT(mShuttingDown);
     695           0 :     return;
     696             :   }
     697             : 
     698             :   // We need this because maybe, mConsumeBodyPump has not been created yet. We
     699             :   // must be sure that we don't try to do it.
     700           1 :   mShuttingDown = true;
     701             : 
     702           1 :   if (mConsumeBodyPump) {
     703           0 :     mConsumeBodyPump->Cancel(NS_BINDING_ABORTED);
     704           0 :     mConsumeBodyPump = nullptr;
     705             :   }
     706             : }
     707             : 
     708             : template <class Derived>
     709             : NS_IMETHODIMP
     710           0 : FetchBodyConsumer<Derived>::Observe(nsISupports* aSubject,
     711             :                                     const char* aTopic,
     712             :                                     const char16_t* aData)
     713             : {
     714           0 :   AssertIsOnMainThread();
     715             : 
     716           0 :   MOZ_ASSERT((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) ||
     717             :              (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0));
     718             : 
     719           0 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
     720           0 :   if (SameCOMIdentity(aSubject, window)) {
     721           0 :     ContinueConsumeBody(NS_BINDING_ABORTED, 0, nullptr);
     722             :   }
     723             : 
     724           0 :   return NS_OK;
     725             : }
     726             : 
     727             : template <class Derived>
     728          13 : NS_IMPL_ADDREF(FetchBodyConsumer<Derived>)
     729             : 
     730             : template <class Derived>
     731          14 : NS_IMPL_RELEASE(FetchBodyConsumer<Derived>)
     732             : 
     733             : template <class Derived>
     734           6 : NS_IMPL_QUERY_INTERFACE(FetchBodyConsumer<Derived>,
     735             :                         nsIObserver,
     736             :                         nsISupportsWeakReference)
     737             : 
     738             : } // namespace dom
     739             : } // namespace mozilla

Generated by: LCOV version 1.13