LCOV - code coverage report
Current view: top level - dom/fetch - Fetch.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 92 408 22.5 %
Date: 2017-07-14 16:53:18 Functions: 15 66 22.7 %
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 "nsIDocument.h"
      11             : #include "nsIGlobalObject.h"
      12             : #include "nsIStreamLoader.h"
      13             : #include "nsIThreadRetargetableRequest.h"
      14             : 
      15             : #include "nsCharSeparatedTokenizer.h"
      16             : #include "nsDOMString.h"
      17             : #include "nsJSUtils.h"
      18             : #include "nsNetUtil.h"
      19             : #include "nsReadableUtils.h"
      20             : #include "nsStreamUtils.h"
      21             : #include "nsStringStream.h"
      22             : #include "nsProxyRelease.h"
      23             : 
      24             : #include "mozilla/ErrorResult.h"
      25             : #include "mozilla/dom/BindingDeclarations.h"
      26             : #include "mozilla/dom/BodyUtil.h"
      27             : #include "mozilla/dom/Exceptions.h"
      28             : #include "mozilla/dom/FetchDriver.h"
      29             : #include "mozilla/dom/File.h"
      30             : #include "mozilla/dom/FormData.h"
      31             : #include "mozilla/dom/Headers.h"
      32             : #include "mozilla/dom/MutableBlobStreamListener.h"
      33             : #include "mozilla/dom/Promise.h"
      34             : #include "mozilla/dom/PromiseWorkerProxy.h"
      35             : #include "mozilla/dom/Request.h"
      36             : #include "mozilla/dom/Response.h"
      37             : #include "mozilla/dom/ScriptSettings.h"
      38             : #include "mozilla/dom/URLSearchParams.h"
      39             : #include "mozilla/dom/workers/ServiceWorkerManager.h"
      40             : #include "mozilla/Telemetry.h"
      41             : 
      42             : #include "BodyExtractor.h"
      43             : #include "FetchObserver.h"
      44             : #include "InternalRequest.h"
      45             : #include "InternalResponse.h"
      46             : 
      47             : #include "WorkerPrivate.h"
      48             : #include "WorkerRunnable.h"
      49             : #include "WorkerScope.h"
      50             : #include "Workers.h"
      51             : 
      52             : namespace mozilla {
      53             : namespace dom {
      54             : 
      55             : using namespace workers;
      56             : 
      57             : // This class helps the proxying of FetchSignal changes cross threads.
      58             : class FetchSignalProxy final : public FetchSignal::Follower
      59             : {
      60             :   // This is created and released on the main-thread.
      61             :   RefPtr<FetchSignal> mSignalMainThread;
      62             : 
      63             :   // The main-thread event target for runnable dispatching.
      64             :   nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
      65             : 
      66             :   // This value is used only for the creation of FetchSignal on the
      67             :   // main-thread. They are not updated.
      68             :   const bool mAborted;
      69             : 
      70             :   // This runnable propagates changes from the FetchSignal on workers to the
      71             :   // FetchSignal on main-thread.
      72           0 :   class FetchSignalProxyRunnable final : public Runnable
      73             :   {
      74             :     RefPtr<FetchSignalProxy> mProxy;
      75             : 
      76             :   public:
      77           0 :     explicit FetchSignalProxyRunnable(FetchSignalProxy* aProxy)
      78           0 :       : Runnable("dom::FetchSignalProxy::FetchSignalProxyRunnable")
      79           0 :       , mProxy(aProxy)
      80           0 :     {}
      81             : 
      82             :     NS_IMETHOD
      83           0 :     Run() override
      84             :     {
      85           0 :       MOZ_ASSERT(NS_IsMainThread());
      86           0 :       FetchSignal* signal = mProxy->GetOrCreateSignalForMainThread();
      87           0 :       signal->Abort();
      88           0 :       return NS_OK;
      89             :     }
      90             :   };
      91             : 
      92             : public:
      93           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchSignalProxy)
      94             : 
      95           0 :   FetchSignalProxy(FetchSignal* aSignal, nsIEventTarget* aMainThreadEventTarget)
      96           0 :     : mMainThreadEventTarget(aMainThreadEventTarget)
      97           0 :     , mAborted(aSignal->Aborted())
      98             :   {
      99           0 :     MOZ_ASSERT(mMainThreadEventTarget);
     100           0 :     Follow(aSignal);
     101           0 :   }
     102             : 
     103             :   void
     104           0 :   Aborted() override
     105             :   {
     106             :     RefPtr<FetchSignalProxyRunnable> runnable =
     107           0 :       new FetchSignalProxyRunnable(this);
     108           0 :     mMainThreadEventTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
     109           0 :   }
     110             : 
     111             :   FetchSignal*
     112           0 :   GetOrCreateSignalForMainThread()
     113             :   {
     114           0 :     MOZ_ASSERT(NS_IsMainThread());
     115           0 :     if (!mSignalMainThread) {
     116           0 :       mSignalMainThread = new FetchSignal(mAborted);
     117             :     }
     118           0 :     return mSignalMainThread;
     119             :   }
     120             : 
     121             :   void
     122           0 :   Shutdown()
     123             :   {
     124           0 :     Unfollow();
     125           0 :   }
     126             : 
     127             : private:
     128           0 :   ~FetchSignalProxy()
     129           0 :   {
     130           0 :     NS_ProxyRelease(
     131             :       "FetchSignalProxy::mSignalMainThread",
     132           0 :       mMainThreadEventTarget, mSignalMainThread.forget());
     133           0 :   }
     134             : };
     135             : 
     136             : class WorkerFetchResolver final : public FetchDriverObserver
     137             : {
     138             :   friend class MainThreadFetchRunnable;
     139             :   friend class WorkerDataAvailableRunnable;
     140             :   friend class WorkerFetchResponseEndBase;
     141             :   friend class WorkerFetchResponseEndRunnable;
     142             :   friend class WorkerFetchResponseRunnable;
     143             : 
     144             :   RefPtr<PromiseWorkerProxy> mPromiseProxy;
     145             :   RefPtr<FetchSignalProxy> mSignalProxy;
     146             :   RefPtr<FetchObserver> mFetchObserver;
     147             : 
     148             : public:
     149             :   // Returns null if worker is shutting down.
     150             :   static already_AddRefed<WorkerFetchResolver>
     151           0 :   Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise,
     152             :          FetchSignal* aSignal, FetchObserver* aObserver)
     153             :   {
     154           0 :     MOZ_ASSERT(aWorkerPrivate);
     155           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     156             :     RefPtr<PromiseWorkerProxy> proxy =
     157           0 :       PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
     158           0 :     if (!proxy) {
     159           0 :       return nullptr;
     160             :     }
     161             : 
     162           0 :     RefPtr<FetchSignalProxy> signalProxy;
     163           0 :     if (aSignal) {
     164             :       signalProxy =
     165           0 :         new FetchSignalProxy(aSignal, aWorkerPrivate->MainThreadEventTarget());
     166             :     }
     167             : 
     168             :     RefPtr<WorkerFetchResolver> r =
     169           0 :       new WorkerFetchResolver(proxy, signalProxy, aObserver);
     170           0 :     return r.forget();
     171             :   }
     172             : 
     173             :   FetchSignal*
     174           0 :   GetFetchSignal()
     175             :   {
     176           0 :     MOZ_ASSERT(NS_IsMainThread());
     177             : 
     178           0 :     if (!mSignalProxy) {
     179           0 :       return nullptr;
     180             :     }
     181             : 
     182           0 :     return mSignalProxy->GetOrCreateSignalForMainThread();
     183             :   }
     184             : 
     185             :   void
     186             :   OnResponseAvailableInternal(InternalResponse* aResponse) override;
     187             : 
     188             :   void
     189             :   OnResponseEnd(FetchDriverObserver::EndReason eReason) override;
     190             : 
     191             :   void
     192             :   OnDataAvailable() override;
     193             : 
     194             : private:
     195           0 :    WorkerFetchResolver(PromiseWorkerProxy* aProxy,
     196             :                        FetchSignalProxy* aSignalProxy,
     197             :                        FetchObserver* aObserver)
     198           0 :     : mPromiseProxy(aProxy)
     199             :     , mSignalProxy(aSignalProxy)
     200           0 :     , mFetchObserver(aObserver)
     201             :   {
     202           0 :     MOZ_ASSERT(!NS_IsMainThread());
     203           0 :     MOZ_ASSERT(mPromiseProxy);
     204           0 :   }
     205             : 
     206           0 :   ~WorkerFetchResolver()
     207           0 :   {}
     208             : 
     209             :   virtual void
     210             :   FlushConsoleReport() override;
     211             : };
     212             : 
     213             : class MainThreadFetchResolver final : public FetchDriverObserver
     214             : {
     215             :   RefPtr<Promise> mPromise;
     216             :   RefPtr<Response> mResponse;
     217             :   RefPtr<FetchObserver> mFetchObserver;
     218             : 
     219             :   nsCOMPtr<nsILoadGroup> mLoadGroup;
     220             : 
     221             :   NS_DECL_OWNINGTHREAD
     222             : public:
     223           1 :   MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver)
     224           1 :     : mPromise(aPromise)
     225           1 :     , mFetchObserver(aObserver)
     226           1 :   {}
     227             : 
     228             :   void
     229             :   OnResponseAvailableInternal(InternalResponse* aResponse) override;
     230             : 
     231           1 :   void SetLoadGroup(nsILoadGroup* aLoadGroup)
     232             :   {
     233           1 :     mLoadGroup = aLoadGroup;
     234           1 :   }
     235             : 
     236             :   void
     237           1 :   OnResponseEnd(FetchDriverObserver::EndReason aReason) override
     238             :   {
     239           1 :     if (aReason == eAborted) {
     240           0 :       mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     241             :     }
     242             : 
     243           1 :     mFetchObserver = nullptr;
     244             : 
     245           1 :     FlushConsoleReport();
     246           1 :   }
     247             : 
     248             :   void
     249             :   OnDataAvailable() override;
     250             : 
     251             : private:
     252             :   ~MainThreadFetchResolver();
     253             : 
     254           1 :   void FlushConsoleReport() override
     255             :   {
     256           1 :     mReporter->FlushConsoleReports(mLoadGroup);
     257           1 :   }
     258             : };
     259             : 
     260           0 : class MainThreadFetchRunnable : public Runnable
     261             : {
     262             :   RefPtr<WorkerFetchResolver> mResolver;
     263             :   RefPtr<InternalRequest> mRequest;
     264             : 
     265             : public:
     266           0 :   MainThreadFetchRunnable(WorkerFetchResolver* aResolver,
     267             :                           InternalRequest* aRequest)
     268           0 :     : Runnable("dom::MainThreadFetchRunnable")
     269             :     , mResolver(aResolver)
     270           0 :     , mRequest(aRequest)
     271             :   {
     272           0 :     MOZ_ASSERT(mResolver);
     273           0 :   }
     274             : 
     275             :   NS_IMETHOD
     276           0 :   Run() override
     277             :   {
     278           0 :     AssertIsOnMainThread();
     279           0 :     RefPtr<FetchDriver> fetch;
     280           0 :     RefPtr<PromiseWorkerProxy> proxy = mResolver->mPromiseProxy;
     281             : 
     282             :     {
     283             :       // Acquire the proxy mutex while getting data from the WorkerPrivate...
     284           0 :       MutexAutoLock lock(proxy->Lock());
     285           0 :       if (proxy->CleanedUp()) {
     286           0 :         NS_WARNING("Aborting Fetch because worker already shut down");
     287           0 :         return NS_OK;
     288             :       }
     289             : 
     290           0 :       WorkerPrivate* workerPrivate = proxy->GetWorkerPrivate();
     291           0 :       MOZ_ASSERT(workerPrivate);
     292           0 :       nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
     293           0 :       MOZ_ASSERT(principal);
     294           0 :       nsCOMPtr<nsILoadGroup> loadGroup = workerPrivate->GetLoadGroup();
     295           0 :       MOZ_ASSERT(loadGroup);
     296             :       // We don't track if a worker is spawned from a tracking script for now,
     297             :       // so pass false as the last argument to FetchDriver().
     298             :       fetch = new FetchDriver(mRequest, principal, loadGroup,
     299           0 :                               workerPrivate->MainThreadEventTarget(), false);
     300           0 :       nsAutoCString spec;
     301           0 :       if (proxy->GetWorkerPrivate()->GetBaseURI()) {
     302           0 :         proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
     303             :       }
     304           0 :       fetch->SetWorkerScript(spec);
     305             :     }
     306             : 
     307           0 :     RefPtr<FetchSignal> signal = mResolver->GetFetchSignal();
     308             : 
     309             :     // ...but release it before calling Fetch, because mResolver's callback can
     310             :     // be called synchronously and they want the mutex, too.
     311           0 :     return fetch->Fetch(signal, mResolver);
     312             :   }
     313             : };
     314             : 
     315             : already_AddRefed<Promise>
     316           1 : FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
     317             :              const RequestInit& aInit, CallerType aCallerType, ErrorResult& aRv)
     318             : {
     319           2 :   RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
     320           1 :   if (NS_WARN_IF(aRv.Failed())) {
     321           0 :     return nullptr;
     322             :   }
     323             : 
     324           1 :   MOZ_ASSERT(aGlobal);
     325             : 
     326             :   // Double check that we have chrome privileges if the Request's content
     327             :   // policy type has been overridden.
     328           1 :   MOZ_ASSERT_IF(aInput.IsRequest() &&
     329             :                 aInput.GetAsRequest().IsContentPolicyTypeOverridden(),
     330             :                 aCallerType == CallerType::System);
     331             : 
     332           2 :   AutoJSAPI jsapi;
     333           1 :   if (!jsapi.Init(aGlobal)) {
     334           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     335           0 :     return nullptr;
     336             :   }
     337             : 
     338           1 :   JSContext* cx = jsapi.cx();
     339           2 :   JS::Rooted<JSObject*> jsGlobal(cx, aGlobal->GetGlobalJSObject());
     340           2 :   GlobalObject global(cx, jsGlobal);
     341             : 
     342           2 :   RefPtr<Request> request = Request::Constructor(global, aInput, aInit, aRv);
     343           1 :   if (NS_WARN_IF(aRv.Failed())) {
     344           0 :     return nullptr;
     345             :   }
     346             : 
     347           2 :   RefPtr<InternalRequest> r = request->GetInternalRequest();
     348             : 
     349           2 :   RefPtr<FetchSignal> signal;
     350           1 :   if (aInit.mSignal.WasPassed()) {
     351           0 :     signal = &aInit.mSignal.Value();
     352             :     // Let's FetchDriver to deal with an already aborted signal.
     353             :   }
     354             : 
     355           2 :   RefPtr<FetchObserver> observer;
     356           1 :   if (aInit.mObserve.WasPassed()) {
     357           0 :     observer = new FetchObserver(aGlobal, signal);
     358           0 :     aInit.mObserve.Value().HandleEvent(*observer);
     359             :   }
     360             : 
     361           1 :   if (NS_IsMainThread()) {
     362           2 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
     363           2 :     nsCOMPtr<nsIDocument> doc;
     364           2 :     nsCOMPtr<nsILoadGroup> loadGroup;
     365             :     nsIPrincipal* principal;
     366           1 :     bool isTrackingFetch = false;
     367           1 :     if (window) {
     368           0 :       doc = window->GetExtantDoc();
     369           0 :       if (!doc) {
     370           0 :         aRv.Throw(NS_ERROR_FAILURE);
     371           0 :         return nullptr;
     372             :       }
     373           0 :       principal = doc->NodePrincipal();
     374           0 :       loadGroup = doc->GetDocumentLoadGroup();
     375             : 
     376           0 :       nsAutoCString fileNameString;
     377           0 :       if (nsJSUtils::GetCallingLocation(cx, fileNameString)) {
     378           0 :         isTrackingFetch = doc->IsScriptTracking(fileNameString);
     379             :       }
     380             :     } else {
     381           1 :       principal = aGlobal->PrincipalOrNull();
     382           1 :       if (NS_WARN_IF(!principal)) {
     383           0 :         aRv.Throw(NS_ERROR_FAILURE);
     384           0 :         return nullptr;
     385             :       }
     386           1 :       nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
     387           1 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     388           0 :         aRv.Throw(rv);
     389           0 :         return nullptr;
     390             :       }
     391             :     }
     392             : 
     393           1 :     Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
     394             : 
     395             :     RefPtr<MainThreadFetchResolver> resolver =
     396           3 :       new MainThreadFetchResolver(p, observer);
     397             :     RefPtr<FetchDriver> fetch =
     398             :       new FetchDriver(r, principal, loadGroup,
     399           3 :                       aGlobal->EventTargetFor(TaskCategory::Other), isTrackingFetch);
     400           1 :     fetch->SetDocument(doc);
     401           1 :     resolver->SetLoadGroup(loadGroup);
     402           1 :     aRv = fetch->Fetch(signal, resolver);
     403           1 :     if (NS_WARN_IF(aRv.Failed())) {
     404           0 :       return nullptr;
     405             :     }
     406             :   } else {
     407           0 :     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     408           0 :     MOZ_ASSERT(worker);
     409             : 
     410           0 :     Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 0);
     411             : 
     412           0 :     if (worker->IsServiceWorker()) {
     413           0 :       r->SetSkipServiceWorker();
     414             :     }
     415             : 
     416             :     RefPtr<WorkerFetchResolver> resolver =
     417           0 :       WorkerFetchResolver::Create(worker, p, signal, observer);
     418           0 :     if (!resolver) {
     419           0 :       NS_WARNING("Could not add WorkerFetchResolver workerHolder to worker");
     420           0 :       aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
     421           0 :       return nullptr;
     422             :     }
     423             : 
     424             :     RefPtr<MainThreadFetchRunnable> run =
     425           0 :       new MainThreadFetchRunnable(resolver, r);
     426           0 :     worker->DispatchToMainThread(run.forget());
     427             :   }
     428             : 
     429           1 :   return p.forget();
     430             : }
     431             : 
     432             : void
     433           1 : MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
     434             : {
     435           1 :   NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
     436           1 :   AssertIsOnMainThread();
     437             : 
     438           1 :   if (aResponse->Type() != ResponseType::Error) {
     439           1 :     if (mFetchObserver) {
     440           0 :       mFetchObserver->SetState(FetchState::Complete);
     441             :     }
     442             : 
     443           2 :     nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
     444           2 :     mResponse = new Response(go, aResponse);
     445           1 :     mPromise->MaybeResolve(mResponse);
     446             :   } else {
     447           0 :     if (mFetchObserver) {
     448           0 :       mFetchObserver->SetState(FetchState::Errored);
     449             :     }
     450             : 
     451           0 :     ErrorResult result;
     452           0 :     result.ThrowTypeError<MSG_FETCH_FAILED>();
     453           0 :     mPromise->MaybeReject(result);
     454             :   }
     455           1 : }
     456             : 
     457             : void
     458           1 : MainThreadFetchResolver::OnDataAvailable()
     459             : {
     460           1 :   NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
     461           1 :   AssertIsOnMainThread();
     462             : 
     463           1 :   if (!mFetchObserver) {
     464           1 :     return;
     465             :   }
     466             : 
     467           0 :   if (mFetchObserver->State() == FetchState::Requesting) {
     468           0 :     mFetchObserver->SetState(FetchState::Responding);
     469             :   }
     470             : }
     471             : 
     472           3 : MainThreadFetchResolver::~MainThreadFetchResolver()
     473             : {
     474           1 :   NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
     475           3 : }
     476             : 
     477           0 : class WorkerFetchResponseRunnable final : public MainThreadWorkerRunnable
     478             : {
     479             :   RefPtr<WorkerFetchResolver> mResolver;
     480             :   // Passed from main thread to worker thread after being initialized.
     481             :   RefPtr<InternalResponse> mInternalResponse;
     482             : public:
     483           0 :   WorkerFetchResponseRunnable(WorkerPrivate* aWorkerPrivate,
     484             :                               WorkerFetchResolver* aResolver,
     485             :                               InternalResponse* aResponse)
     486           0 :     : MainThreadWorkerRunnable(aWorkerPrivate)
     487             :     , mResolver(aResolver)
     488           0 :     , mInternalResponse(aResponse)
     489             :   {
     490           0 :      MOZ_ASSERT(mResolver);
     491           0 :   }
     492             : 
     493             :   bool
     494           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     495             :   {
     496           0 :     MOZ_ASSERT(aWorkerPrivate);
     497           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     498             : 
     499           0 :     RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise();
     500             : 
     501           0 :     if (mInternalResponse->Type() != ResponseType::Error) {
     502           0 :       if (mResolver->mFetchObserver) {
     503           0 :         mResolver->mFetchObserver->SetState(FetchState::Complete);
     504             :       }
     505             : 
     506           0 :       RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
     507           0 :       RefPtr<Response> response = new Response(global, mInternalResponse);
     508           0 :       promise->MaybeResolve(response);
     509             :     } else {
     510           0 :       if (mResolver->mFetchObserver) {
     511           0 :         mResolver->mFetchObserver->SetState(FetchState::Errored);
     512             :       }
     513             : 
     514           0 :       ErrorResult result;
     515           0 :       result.ThrowTypeError<MSG_FETCH_FAILED>();
     516           0 :       promise->MaybeReject(result);
     517             :     }
     518           0 :     return true;
     519             :   }
     520             : };
     521             : 
     522           0 : class WorkerDataAvailableRunnable final : public MainThreadWorkerRunnable
     523             : {
     524             :   RefPtr<WorkerFetchResolver> mResolver;
     525             : public:
     526           0 :   WorkerDataAvailableRunnable(WorkerPrivate* aWorkerPrivate,
     527             :                               WorkerFetchResolver* aResolver)
     528           0 :     : MainThreadWorkerRunnable(aWorkerPrivate)
     529           0 :     , mResolver(aResolver)
     530             :   {
     531           0 :   }
     532             : 
     533             :   bool
     534           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     535             :   {
     536           0 :     MOZ_ASSERT(aWorkerPrivate);
     537           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     538             : 
     539           0 :     if (mResolver->mFetchObserver &&
     540           0 :         mResolver->mFetchObserver->State() == FetchState::Requesting) {
     541           0 :       mResolver->mFetchObserver->SetState(FetchState::Responding);
     542             :     }
     543             : 
     544           0 :     return true;
     545             :   }
     546             : };
     547             : 
     548           0 : class WorkerFetchResponseEndBase
     549             : {
     550             : protected:
     551             :   RefPtr<WorkerFetchResolver> mResolver;
     552             : 
     553             : public:
     554           0 :   explicit WorkerFetchResponseEndBase(WorkerFetchResolver* aResolver)
     555           0 :     : mResolver(aResolver)
     556             :   {
     557           0 :     MOZ_ASSERT(aResolver);
     558           0 :   }
     559             : 
     560             :   void
     561           0 :   WorkerRunInternal(WorkerPrivate* aWorkerPrivate)
     562             :   {
     563           0 :     MOZ_ASSERT(aWorkerPrivate);
     564           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     565             : 
     566           0 :     mResolver->mPromiseProxy->CleanUp();
     567             : 
     568           0 :     mResolver->mFetchObserver = nullptr;
     569             : 
     570           0 :     if (mResolver->mSignalProxy) {
     571           0 :       mResolver->mSignalProxy->Shutdown();
     572           0 :       mResolver->mSignalProxy = nullptr;
     573             :     }
     574           0 :   }
     575             : };
     576             : 
     577           0 : class WorkerFetchResponseEndRunnable final : public MainThreadWorkerRunnable
     578             :                                            , public WorkerFetchResponseEndBase
     579             : {
     580             :   FetchDriverObserver::EndReason mReason;
     581             : 
     582             : public:
     583           0 :   WorkerFetchResponseEndRunnable(WorkerPrivate* aWorkerPrivate,
     584             :                                  WorkerFetchResolver* aResolver,
     585             :                                  FetchDriverObserver::EndReason aReason)
     586           0 :     : MainThreadWorkerRunnable(aWorkerPrivate)
     587             :     , WorkerFetchResponseEndBase(aResolver)
     588           0 :     , mReason(aReason)
     589             :   {
     590           0 :   }
     591             : 
     592             :   bool
     593           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     594             :   {
     595           0 :     if (mReason == FetchDriverObserver::eAborted) {
     596           0 :       RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise();
     597           0 :       promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     598             :     }
     599             : 
     600           0 :     WorkerRunInternal(aWorkerPrivate);
     601           0 :     return true;
     602             :   }
     603             : 
     604             :   nsresult
     605           0 :   Cancel() override
     606             :   {
     607             :     // Execute Run anyway to make sure we cleanup our promise proxy to avoid
     608             :     // leaking the worker thread
     609           0 :     Run();
     610           0 :     return WorkerRunnable::Cancel();
     611             :   }
     612             : };
     613             : 
     614           0 : class WorkerFetchResponseEndControlRunnable final : public MainThreadWorkerControlRunnable
     615             :                                                   , public WorkerFetchResponseEndBase
     616             : {
     617             : public:
     618           0 :   WorkerFetchResponseEndControlRunnable(WorkerPrivate* aWorkerPrivate,
     619             :                                         WorkerFetchResolver* aResolver)
     620           0 :     : MainThreadWorkerControlRunnable(aWorkerPrivate)
     621           0 :     , WorkerFetchResponseEndBase(aResolver)
     622             :   {
     623           0 :   }
     624             : 
     625             :   bool
     626           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     627             :   {
     628           0 :     WorkerRunInternal(aWorkerPrivate);
     629           0 :     return true;
     630             :   }
     631             : 
     632             :   // Control runnable cancel already calls Run().
     633             : };
     634             : 
     635             : void
     636           0 : WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
     637             : {
     638           0 :   AssertIsOnMainThread();
     639             : 
     640           0 :   MutexAutoLock lock(mPromiseProxy->Lock());
     641           0 :   if (mPromiseProxy->CleanedUp()) {
     642           0 :     return;
     643             :   }
     644             : 
     645             :   RefPtr<WorkerFetchResponseRunnable> r =
     646           0 :     new WorkerFetchResponseRunnable(mPromiseProxy->GetWorkerPrivate(), this,
     647           0 :                                     aResponse);
     648             : 
     649           0 :   if (!r->Dispatch()) {
     650           0 :     NS_WARNING("Could not dispatch fetch response");
     651             :   }
     652             : }
     653             : 
     654             : void
     655           0 : WorkerFetchResolver::OnDataAvailable()
     656             : {
     657           0 :   AssertIsOnMainThread();
     658             : 
     659           0 :   MutexAutoLock lock(mPromiseProxy->Lock());
     660           0 :   if (mPromiseProxy->CleanedUp()) {
     661           0 :     return;
     662             :   }
     663             : 
     664             :   RefPtr<WorkerDataAvailableRunnable> r =
     665           0 :     new WorkerDataAvailableRunnable(mPromiseProxy->GetWorkerPrivate(), this);
     666           0 :   Unused << r->Dispatch();
     667             : }
     668             : 
     669             : void
     670           0 : WorkerFetchResolver::OnResponseEnd(FetchDriverObserver::EndReason aReason)
     671             : {
     672           0 :   AssertIsOnMainThread();
     673           0 :   MutexAutoLock lock(mPromiseProxy->Lock());
     674           0 :   if (mPromiseProxy->CleanedUp()) {
     675           0 :     return;
     676             :   }
     677             : 
     678           0 :   FlushConsoleReport();
     679             : 
     680             :   RefPtr<WorkerFetchResponseEndRunnable> r =
     681           0 :     new WorkerFetchResponseEndRunnable(mPromiseProxy->GetWorkerPrivate(),
     682           0 :                                        this, aReason);
     683             : 
     684           0 :   if (!r->Dispatch()) {
     685             :     RefPtr<WorkerFetchResponseEndControlRunnable> cr =
     686           0 :       new WorkerFetchResponseEndControlRunnable(mPromiseProxy->GetWorkerPrivate(),
     687           0 :                                                 this);
     688             :     // This can fail if the worker thread is canceled or killed causing
     689             :     // the PromiseWorkerProxy to give up its WorkerHolder immediately,
     690             :     // allowing the worker thread to become Dead.
     691           0 :     if (!cr->Dispatch()) {
     692           0 :       NS_WARNING("Failed to dispatch WorkerFetchResponseEndControlRunnable");
     693             :     }
     694             :   }
     695             : }
     696             : 
     697             : void
     698           0 : WorkerFetchResolver::FlushConsoleReport()
     699             : {
     700           0 :   AssertIsOnMainThread();
     701           0 :   MOZ_ASSERT(mPromiseProxy);
     702             : 
     703           0 :   if(!mReporter) {
     704           0 :     return;
     705             :   }
     706             : 
     707           0 :   workers::WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
     708           0 :   if (!worker) {
     709           0 :     mReporter->FlushReportsToConsole(0);
     710           0 :     return;
     711             :   }
     712             : 
     713           0 :   if (worker->IsServiceWorker()) {
     714             :     // Flush to service worker
     715           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     716           0 :     if (!swm) {
     717           0 :       mReporter->FlushReportsToConsole(0);
     718           0 :       return;
     719             :     }
     720             : 
     721           0 :     swm->FlushReportsToAllClients(worker->ServiceWorkerScope(), mReporter);
     722           0 :     return;
     723             :   }
     724             : 
     725           0 :   if (worker->IsSharedWorker()) {
     726             :     // Flush to shared worker
     727           0 :     worker->FlushReportsToSharedWorkers(mReporter);
     728           0 :     return;
     729             :   }
     730             : 
     731             :   // Flush to dedicated worker
     732           0 :   mReporter->FlushConsoleReports(worker->GetLoadGroup());
     733             : }
     734             : 
     735             : nsresult
     736           0 : ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
     737             :                           nsIInputStream** aStream,
     738             :                           nsCString& aContentTypeWithCharset,
     739             :                           uint64_t& aContentLength)
     740             : {
     741           0 :   MOZ_ASSERT(aStream);
     742           0 :   nsAutoCString charset;
     743           0 :   aContentTypeWithCharset.SetIsVoid(true);
     744             : 
     745           0 :   if (aBodyInit.IsArrayBuffer()) {
     746           0 :     BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
     747           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     748           0 :                             charset);
     749             :   }
     750             : 
     751           0 :   if (aBodyInit.IsArrayBufferView()) {
     752           0 :     BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
     753           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     754           0 :                             charset);
     755             :   }
     756             : 
     757           0 :   if (aBodyInit.IsBlob()) {
     758           0 :     Blob& blob = aBodyInit.GetAsBlob();
     759           0 :     BodyExtractor<nsIXHRSendable> body(&blob);
     760           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     761           0 :                             charset);
     762             :   }
     763             : 
     764           0 :   if (aBodyInit.IsFormData()) {
     765           0 :     FormData& formData = aBodyInit.GetAsFormData();
     766           0 :     BodyExtractor<nsIXHRSendable> body(&formData);
     767           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     768           0 :                             charset);
     769             :   }
     770             : 
     771           0 :   if (aBodyInit.IsUSVString()) {
     772           0 :     BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
     773           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     774           0 :                             charset);
     775             :   }
     776             : 
     777           0 :   if (aBodyInit.IsURLSearchParams()) {
     778           0 :     URLSearchParams& usp = aBodyInit.GetAsURLSearchParams();
     779           0 :     BodyExtractor<nsIXHRSendable> body(&usp);
     780           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     781           0 :                             charset);
     782             :   }
     783             : 
     784           0 :   NS_NOTREACHED("Should never reach here");
     785           0 :   return NS_ERROR_FAILURE;
     786             : }
     787             : 
     788             : nsresult
     789           0 : ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
     790             :                           nsIInputStream** aStream,
     791             :                           nsCString& aContentTypeWithCharset,
     792             :                           uint64_t& aContentLength)
     793             : {
     794           0 :   MOZ_ASSERT(aStream);
     795           0 :   MOZ_ASSERT(!*aStream);
     796             : 
     797           0 :   nsAutoCString charset;
     798           0 :   aContentTypeWithCharset.SetIsVoid(true);
     799             : 
     800           0 :   if (aBodyInit.IsArrayBuffer()) {
     801           0 :     BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
     802           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     803           0 :                             charset);
     804             :   }
     805             : 
     806           0 :   if (aBodyInit.IsArrayBufferView()) {
     807           0 :     BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
     808           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     809           0 :                             charset);
     810             :   }
     811             : 
     812           0 :   if (aBodyInit.IsBlob()) {
     813           0 :     BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsBlob());
     814           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     815           0 :                             charset);
     816             :   }
     817             : 
     818           0 :   if (aBodyInit.IsFormData()) {
     819           0 :     BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsFormData());
     820           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     821           0 :                             charset);
     822             :   }
     823             : 
     824           0 :   if (aBodyInit.IsUSVString()) {
     825           0 :     BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
     826           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     827           0 :                             charset);
     828             :   }
     829             : 
     830           0 :   if (aBodyInit.IsURLSearchParams()) {
     831           0 :     BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsURLSearchParams());
     832           0 :     return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
     833           0 :                             charset);
     834             :   }
     835             : 
     836           0 :   NS_NOTREACHED("Should never reach here");
     837           0 :   return NS_ERROR_FAILURE;
     838             : }
     839             : 
     840             : template <class Derived>
     841           2 : FetchBody<Derived>::FetchBody(nsIGlobalObject* aOwner)
     842             :   : mOwner(aOwner)
     843             :   , mWorkerPrivate(nullptr)
     844           2 :   , mBodyUsed(false)
     845             : {
     846           2 :   MOZ_ASSERT(aOwner);
     847             : 
     848           2 :   if (!NS_IsMainThread()) {
     849           0 :     mWorkerPrivate = GetCurrentThreadWorkerPrivate();
     850           0 :     MOZ_ASSERT(mWorkerPrivate);
     851           0 :     mMainThreadEventTarget = mWorkerPrivate->MainThreadEventTarget();
     852             :   } else {
     853           2 :     mMainThreadEventTarget = aOwner->EventTargetFor(TaskCategory::Other);
     854             :   }
     855             : 
     856           2 :   MOZ_ASSERT(mMainThreadEventTarget);
     857           2 : }
     858             : 
     859             : template
     860             : FetchBody<Request>::FetchBody(nsIGlobalObject* aOwner);
     861             : 
     862             : template
     863             : FetchBody<Response>::FetchBody(nsIGlobalObject* aOwner);
     864             : 
     865             : template <class Derived>
     866           1 : FetchBody<Derived>::~FetchBody()
     867             : {
     868           1 : }
     869             : 
     870             : template <class Derived>
     871             : already_AddRefed<Promise>
     872           1 : FetchBody<Derived>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv)
     873             : {
     874           1 :   if (BodyUsed()) {
     875           0 :     aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
     876           0 :     return nullptr;
     877             :   }
     878             : 
     879           1 :   SetBodyUsed();
     880             : 
     881             :   RefPtr<Promise> promise =
     882             :     FetchBodyConsumer<Derived>::Create(DerivedClass()->GetParentObject(),
     883             :                                        mMainThreadEventTarget, this, aType,
     884           2 :                                        aRv);
     885           1 :   if (NS_WARN_IF(aRv.Failed())) {
     886           0 :     return nullptr;
     887             :   }
     888             : 
     889           1 :   return promise.forget();
     890             : }
     891             : 
     892             : template
     893             : already_AddRefed<Promise>
     894             : FetchBody<Request>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
     895             : 
     896             : template
     897             : already_AddRefed<Promise>
     898             : FetchBody<Response>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
     899             : 
     900             : template <class Derived>
     901             : void
     902           3 : FetchBody<Derived>::SetMimeType()
     903             : {
     904             :   // Extract mime type.
     905           6 :   ErrorResult result;
     906           6 :   nsCString contentTypeValues;
     907           3 :   MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
     908           3 :   DerivedClass()->GetInternalHeaders()->Get(NS_LITERAL_CSTRING("Content-Type"),
     909             :                                             contentTypeValues, result);
     910           3 :   MOZ_ALWAYS_TRUE(!result.Failed());
     911             : 
     912             :   // HTTP ABNF states Content-Type may have only one value.
     913             :   // This is from the "parse a header value" of the fetch spec.
     914           3 :   if (!contentTypeValues.IsVoid() && contentTypeValues.Find(",") == -1) {
     915           1 :     mMimeType = contentTypeValues;
     916           1 :     ToLowerCase(mMimeType);
     917             :   }
     918           3 : }
     919             : 
     920             : template
     921             : void
     922             : FetchBody<Request>::SetMimeType();
     923             : 
     924             : template
     925             : void
     926             : FetchBody<Response>::SetMimeType();
     927             : 
     928             : } // namespace dom
     929             : } // namespace mozilla

Generated by: LCOV version 1.13