LCOV - code coverage report
Current view: top level - dom/xhr - XMLHttpRequestWorker.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 444 1081 41.1 %
Date: 2017-07-14 16:53:18 Functions: 69 143 48.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "XMLHttpRequestWorker.h"
       8             : 
       9             : #include "nsIDOMEvent.h"
      10             : #include "nsIDOMEventListener.h"
      11             : #include "nsIRunnable.h"
      12             : #include "nsIXMLHttpRequest.h"
      13             : #include "nsIXPConnect.h"
      14             : 
      15             : #include "jsfriendapi.h"
      16             : #include "js/TracingAPI.h"
      17             : #include "js/GCPolicyAPI.h"
      18             : #include "mozilla/ArrayUtils.h"
      19             : #include "mozilla/dom/Exceptions.h"
      20             : #include "mozilla/dom/File.h"
      21             : #include "mozilla/dom/FormData.h"
      22             : #include "mozilla/dom/ProgressEvent.h"
      23             : #include "mozilla/dom/StructuredCloneHolder.h"
      24             : #include "mozilla/dom/URLSearchParams.h"
      25             : #include "mozilla/Telemetry.h"
      26             : #include "nsComponentManagerUtils.h"
      27             : #include "nsContentUtils.h"
      28             : #include "nsJSUtils.h"
      29             : #include "nsThreadUtils.h"
      30             : #include "nsVariant.h"
      31             : 
      32             : #include "RuntimeService.h"
      33             : #include "WorkerScope.h"
      34             : #include "WorkerPrivate.h"
      35             : #include "WorkerRunnable.h"
      36             : #include "XMLHttpRequestUpload.h"
      37             : 
      38             : #include "mozilla/UniquePtr.h"
      39             : 
      40             : namespace mozilla {
      41             : namespace dom {
      42             : 
      43             : using namespace workers;
      44             : 
      45             : /* static */ void
      46           0 : XMLHttpRequestWorker::StateData::trace(JSTracer *aTrc)
      47             : {
      48           0 :   JS::TraceEdge(aTrc, &mResponse, "XMLHttpRequestWorker::StateData::mResponse");
      49           0 : }
      50             : 
      51             : /**
      52             :  *  XMLHttpRequest in workers
      53             :  *
      54             :  *  XHR in workers is implemented by proxying calls/events/etc between the
      55             :  *  worker thread and an XMLHttpRequest on the main thread.  The glue
      56             :  *  object here is the Proxy, which lives on both threads.  All other objects
      57             :  *  live on either the main thread (the XMLHttpRequest) or the worker thread
      58             :  *  (the worker and XHR private objects).
      59             :  *
      60             :  *  The main thread XHR is always operated in async mode, even for sync XHR
      61             :  *  in workers.  Calls made on the worker thread are proxied to the main thread
      62             :  *  synchronously (meaning the worker thread is blocked until the call
      63             :  *  returns).  Each proxied call spins up a sync queue, which captures any
      64             :  *  synchronously dispatched events and ensures that they run synchronously
      65             :  *  on the worker as well.  Asynchronously dispatched events are posted to the
      66             :  *  worker thread to run asynchronously.  Some of the XHR state is mirrored on
      67             :  *  the worker thread to avoid needing a cross-thread call on every property
      68             :  *  access.
      69             :  *
      70             :  *  The XHR private is stored in the private slot of the XHR JSObject on the
      71             :  *  worker thread.  It is destroyed when that JSObject is GCd.  The private
      72             :  *  roots its JSObject while network activity is in progress.  It also
      73             :  *  adds itself as a feature to the worker to give itself a chance to clean up
      74             :  *  if the worker goes away during an XHR call.  It is important that the
      75             :  *  rooting and feature registration (collectively called pinning) happens at
      76             :  *  the proper times.  If we pin for too long we can cause memory leaks or even
      77             :  *  shutdown hangs.  If we don't pin for long enough we introduce a GC hazard.
      78             :  *
      79             :  *  The XHR is pinned from the time Send is called to roughly the time loadend
      80             :  *  is received.  There are some complications involved with Abort and XHR
      81             :  *  reuse.  We maintain a counter on the main thread of how many times Send was
      82             :  *  called on this XHR, and we decrement the counter every time we receive a
      83             :  *  loadend event.  When the counter reaches zero we dispatch a runnable to the
      84             :  *  worker thread to unpin the XHR.  We only decrement the counter if the
      85             :  *  dispatch was successful, because the worker may no longer be accepting
      86             :  *  regular runnables.  In the event that we reach Proxy::Teardown and there
      87             :  *  the outstanding Send count is still non-zero, we dispatch a control
      88             :  *  runnable which is guaranteed to run.
      89             :  *
      90             :  *  NB: Some of this could probably be simplified now that we have the
      91             :  *  inner/outer channel ids.
      92             :  */
      93             : 
      94             : class Proxy final : public nsIDOMEventListener
      95             : {
      96             : public:
      97             :   // Read on multiple threads.
      98             :   WorkerPrivate* mWorkerPrivate;
      99             :   XMLHttpRequestWorker* mXMLHttpRequestPrivate;
     100             : 
     101             :   // XHR Params:
     102             :   bool mMozAnon;
     103             :   bool mMozSystem;
     104             : 
     105             :   // Only touched on the main thread.
     106             :   RefPtr<XMLHttpRequestMainThread> mXHR;
     107             :   nsCOMPtr<nsIXMLHttpRequestUpload> mXHRUpload;
     108             :   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
     109             :   nsCOMPtr<nsIEventTarget> mSyncEventResponseTarget;
     110             :   uint32_t mInnerEventStreamId;
     111             :   uint32_t mInnerChannelId;
     112             :   uint32_t mOutstandingSendCount;
     113             : 
     114             :   // Only touched on the worker thread.
     115             :   uint32_t mOuterEventStreamId;
     116             :   uint32_t mOuterChannelId;
     117             :   uint32_t mOpenCount;
     118             :   uint64_t mLastLoaded;
     119             :   uint64_t mLastTotal;
     120             :   uint64_t mLastUploadLoaded;
     121             :   uint64_t mLastUploadTotal;
     122             :   bool mIsSyncXHR;
     123             :   bool mLastLengthComputable;
     124             :   bool mLastUploadLengthComputable;
     125             :   bool mSeenLoadStart;
     126             :   bool mSeenUploadLoadStart;
     127             : 
     128             :   // Only touched on the main thread.
     129             :   bool mUploadEventListenersAttached;
     130             :   bool mMainThreadSeenLoadStart;
     131             :   bool mInOpen;
     132             :   bool mArrayBufferResponseWasTransferred;
     133             : 
     134             : public:
     135           3 :   Proxy(XMLHttpRequestWorker* aXHRPrivate, bool aMozAnon, bool aMozSystem)
     136           3 :   : mWorkerPrivate(nullptr), mXMLHttpRequestPrivate(aXHRPrivate),
     137             :     mMozAnon(aMozAnon), mMozSystem(aMozSystem),
     138             :     mInnerEventStreamId(0), mInnerChannelId(0), mOutstandingSendCount(0),
     139             :     mOuterEventStreamId(0), mOuterChannelId(0), mOpenCount(0), mLastLoaded(0),
     140             :     mLastTotal(0), mLastUploadLoaded(0), mLastUploadTotal(0), mIsSyncXHR(false),
     141             :     mLastLengthComputable(false), mLastUploadLengthComputable(false),
     142             :     mSeenLoadStart(false), mSeenUploadLoadStart(false),
     143             :     mUploadEventListenersAttached(false), mMainThreadSeenLoadStart(false),
     144           3 :     mInOpen(false), mArrayBufferResponseWasTransferred(false)
     145           3 :   { }
     146             : 
     147             :   NS_DECL_THREADSAFE_ISUPPORTS
     148             :   NS_DECL_NSIDOMEVENTLISTENER
     149             : 
     150             :   bool
     151             :   Init();
     152             : 
     153             :   void
     154             :   Teardown(bool aSendUnpin);
     155             : 
     156             :   bool
     157             :   AddRemoveEventListeners(bool aUpload, bool aAdd);
     158             : 
     159             :   void
     160           2 :   Reset()
     161             :   {
     162           2 :     AssertIsOnMainThread();
     163             : 
     164           2 :     if (mUploadEventListenersAttached) {
     165           2 :       AddRemoveEventListeners(true, false);
     166             :     }
     167           2 :   }
     168             : 
     169             :   already_AddRefed<nsIEventTarget>
     170          19 :   GetEventTarget()
     171             :   {
     172          19 :     AssertIsOnMainThread();
     173             : 
     174             :     nsCOMPtr<nsIEventTarget> target = mSyncEventResponseTarget ?
     175             :                                       mSyncEventResponseTarget :
     176          38 :                                       mSyncLoopTarget;
     177          38 :     return target.forget();
     178             :   }
     179             : 
     180             : private:
     181           0 :   ~Proxy()
     182           0 :   {
     183           0 :     MOZ_ASSERT(!mXHR);
     184           0 :     MOZ_ASSERT(!mXHRUpload);
     185           0 :     MOZ_ASSERT(!mOutstandingSendCount);
     186           0 :   }
     187             : };
     188             : 
     189             : class WorkerThreadProxySyncRunnable : public WorkerMainThreadRunnable
     190             : {
     191             : protected:
     192             :   RefPtr<Proxy> mProxy;
     193             : 
     194             : private:
     195             :   // mErrorCode is set on the main thread by MainThreadRun and it's used to at
     196             :   // the end of the Dispatch() to return the error code.
     197             :   nsresult mErrorCode;
     198             : 
     199             : public:
     200           8 :   WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
     201          16 :   : WorkerMainThreadRunnable(aWorkerPrivate, NS_LITERAL_CSTRING("XHR"))
     202             :   , mProxy(aProxy)
     203          16 :   , mErrorCode(NS_OK)
     204             :   {
     205           8 :     MOZ_ASSERT(aWorkerPrivate);
     206           8 :     MOZ_ASSERT(aProxy);
     207           8 :     aWorkerPrivate->AssertIsOnWorkerThread();
     208           8 :   }
     209             : 
     210             :   void
     211           8 :   Dispatch(Status aFailStatus, ErrorResult& aRv)
     212             :   {
     213           8 :     WorkerMainThreadRunnable::Dispatch(aFailStatus, aRv);
     214           7 :     if (NS_WARN_IF(aRv.Failed())) {
     215           0 :       return;
     216             :     }
     217             : 
     218           7 :     if (NS_FAILED(mErrorCode)) {
     219           0 :       aRv.Throw(mErrorCode);
     220             :     }
     221             :   }
     222             : 
     223             : protected:
     224           7 :   virtual ~WorkerThreadProxySyncRunnable()
     225           7 :   { }
     226             : 
     227             :   virtual void
     228             :   RunOnMainThread(ErrorResult& aRv) = 0;
     229             : 
     230             : private:
     231             :   virtual bool MainThreadRun() override;
     232             : };
     233             : 
     234             : class SendRunnable final
     235             :   : public WorkerThreadProxySyncRunnable
     236             :   , public StructuredCloneHolder
     237             : {
     238             :   nsString mStringBody;
     239             :   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
     240             :   bool mHasUploadListeners;
     241             : 
     242             : public:
     243           2 :   SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     244             :                const nsAString& aStringBody)
     245           2 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
     246             :   , StructuredCloneHolder(CloningSupported, TransferringNotSupported,
     247             :                           StructuredCloneScope::SameProcessDifferentThread)
     248             :   , mStringBody(aStringBody)
     249           2 :   , mHasUploadListeners(false)
     250             :   {
     251           2 :   }
     252             : 
     253           2 :   void SetHaveUploadListeners(bool aHasUploadListeners)
     254             :   {
     255           2 :     mHasUploadListeners = aHasUploadListeners;
     256           2 :   }
     257             : 
     258           2 :   void SetSyncLoopTarget(nsIEventTarget* aSyncLoopTarget)
     259             :   {
     260           2 :     mSyncLoopTarget = aSyncLoopTarget;
     261           2 :   }
     262             : 
     263             : private:
     264           4 :   ~SendRunnable()
     265           6 :   { }
     266             : 
     267             :   virtual void
     268             :   RunOnMainThread(ErrorResult& aRv) override;
     269             : };
     270             : 
     271             : namespace {
     272             : 
     273             : enum
     274             : {
     275             :   STRING_abort = 0,
     276             :   STRING_error,
     277             :   STRING_load,
     278             :   STRING_loadstart,
     279             :   STRING_progress,
     280             :   STRING_timeout,
     281             :   STRING_readystatechange,
     282             :   STRING_loadend,
     283             : 
     284             :   STRING_COUNT,
     285             : 
     286             :   STRING_LAST_XHR = STRING_loadend,
     287             :   STRING_LAST_EVENTTARGET = STRING_timeout
     288             : };
     289             : 
     290             : static_assert(STRING_LAST_XHR >= STRING_LAST_EVENTTARGET, "Bad string setup!");
     291             : static_assert(STRING_LAST_XHR == STRING_COUNT - 1, "Bad string setup!");
     292             : 
     293             : const char* const sEventStrings[] = {
     294             :   // nsIXMLHttpRequestEventTarget event types, supported by both XHR and Upload.
     295             :   "abort",
     296             :   "error",
     297             :   "load",
     298             :   "loadstart",
     299             :   "progress",
     300             :   "timeout",
     301             : 
     302             :   // nsIXMLHttpRequest event types, supported only by XHR.
     303             :   "readystatechange",
     304             :   "loadend",
     305             : };
     306             : 
     307             : static_assert(MOZ_ARRAY_LENGTH(sEventStrings) == STRING_COUNT,
     308             :               "Bad string count!");
     309             : 
     310             : class MainThreadProxyRunnable : public MainThreadWorkerSyncRunnable
     311             : {
     312             : protected:
     313             :   RefPtr<Proxy> mProxy;
     314             : 
     315          19 :   MainThreadProxyRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
     316          38 :   : MainThreadWorkerSyncRunnable(aWorkerPrivate, aProxy->GetEventTarget()),
     317          38 :     mProxy(aProxy)
     318             :   {
     319          19 :     MOZ_ASSERT(aProxy);
     320          19 :   }
     321             : 
     322          19 :   virtual ~MainThreadProxyRunnable()
     323          19 :   { }
     324             : };
     325             : 
     326             : class XHRUnpinRunnable final : public MainThreadWorkerControlRunnable
     327             : {
     328             :   XMLHttpRequestWorker* mXMLHttpRequestPrivate;
     329             : 
     330             : public:
     331           0 :   XHRUnpinRunnable(WorkerPrivate* aWorkerPrivate,
     332             :                    XMLHttpRequestWorker* aXHRPrivate)
     333           0 :   : MainThreadWorkerControlRunnable(aWorkerPrivate),
     334           0 :     mXMLHttpRequestPrivate(aXHRPrivate)
     335             :   {
     336           0 :     MOZ_ASSERT(aXHRPrivate);
     337           0 :   }
     338             : 
     339             : private:
     340           0 :   ~XHRUnpinRunnable()
     341           0 :   { }
     342             : 
     343             :   bool
     344           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
     345             :   {
     346           0 :     if (mXMLHttpRequestPrivate->SendInProgress()) {
     347           0 :       mXMLHttpRequestPrivate->Unpin();
     348             :     }
     349             : 
     350           0 :     return true;
     351             :   }
     352             : };
     353             : 
     354             : class AsyncTeardownRunnable final : public Runnable
     355             : {
     356             :   RefPtr<Proxy> mProxy;
     357             : 
     358             : public:
     359           0 :   explicit AsyncTeardownRunnable(Proxy* aProxy)
     360           0 :     : Runnable("dom::AsyncTeardownRunnable")
     361           0 :     , mProxy(aProxy)
     362             :   {
     363           0 :     MOZ_ASSERT(aProxy);
     364           0 :   }
     365             : 
     366             : private:
     367           0 :   ~AsyncTeardownRunnable()
     368           0 :   { }
     369             : 
     370             :   NS_IMETHOD
     371           0 :   Run() override
     372             :   {
     373           0 :     AssertIsOnMainThread();
     374             : 
     375             :     // This means the XHR was GC'd, so we can't be pinned, and we don't need to
     376             :     // try to unpin.
     377           0 :     mProxy->Teardown(/* aSendUnpin */ false);
     378           0 :     mProxy = nullptr;
     379             : 
     380           0 :     return NS_OK;
     381             :   }
     382             : };
     383             : 
     384             : class LoadStartDetectionRunnable final : public Runnable,
     385             :                                          public nsIDOMEventListener
     386             : {
     387             :   WorkerPrivate* mWorkerPrivate;
     388             :   RefPtr<Proxy> mProxy;
     389             :   RefPtr<XMLHttpRequest> mXHR;
     390             :   XMLHttpRequestWorker* mXMLHttpRequestPrivate;
     391             :   nsString mEventType;
     392             :   uint32_t mChannelId;
     393             :   bool mReceivedLoadStart;
     394             : 
     395             :   class ProxyCompleteRunnable final : public MainThreadProxyRunnable
     396             :   {
     397             :     XMLHttpRequestWorker* mXMLHttpRequestPrivate;
     398             :     uint32_t mChannelId;
     399             : 
     400             :   public:
     401           2 :     ProxyCompleteRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     402             :                           XMLHttpRequestWorker* aXHRPrivate, uint32_t aChannelId)
     403           2 :     : MainThreadProxyRunnable(aWorkerPrivate, aProxy),
     404           2 :       mXMLHttpRequestPrivate(aXHRPrivate), mChannelId(aChannelId)
     405           2 :     { }
     406             : 
     407             :   private:
     408           4 :     ~ProxyCompleteRunnable()
     409           6 :     { }
     410             : 
     411             :     virtual bool
     412           2 :     WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     413             :     {
     414           2 :       if (mChannelId != mProxy->mOuterChannelId) {
     415             :         // Threads raced, this event is now obsolete.
     416           0 :         return true;
     417             :       }
     418             : 
     419           2 :       if (mSyncLoopTarget) {
     420           2 :         aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, true);
     421             :       }
     422             : 
     423           2 :       if (mXMLHttpRequestPrivate->SendInProgress()) {
     424           2 :         mXMLHttpRequestPrivate->Unpin();
     425             :       }
     426             : 
     427           2 :       return true;
     428             :     }
     429             : 
     430             :     nsresult
     431           0 :     Cancel() override
     432             :     {
     433             :       // This must run!
     434           0 :       nsresult rv = MainThreadProxyRunnable::Cancel();
     435           0 :       nsresult rv2 = Run();
     436           0 :       return NS_FAILED(rv) ? rv : rv2;
     437             :     }
     438             :   };
     439             : 
     440             : public:
     441           2 :   LoadStartDetectionRunnable(Proxy* aProxy, XMLHttpRequestWorker* aXHRPrivate)
     442           2 :     : Runnable("dom::LoadStartDetectionRunnable")
     443           2 :     , mWorkerPrivate(aProxy->mWorkerPrivate)
     444             :     , mProxy(aProxy)
     445             :     , mXHR(aProxy->mXHR)
     446             :     , mXMLHttpRequestPrivate(aXHRPrivate)
     447           2 :     , mChannelId(mProxy->mInnerChannelId)
     448           6 :     , mReceivedLoadStart(false)
     449             :   {
     450           2 :     AssertIsOnMainThread();
     451           2 :     mEventType.AssignWithConversion(sEventStrings[STRING_loadstart]);
     452           2 :   }
     453             : 
     454             :   NS_DECL_ISUPPORTS_INHERITED
     455             :   NS_DECL_NSIRUNNABLE
     456             :   NS_DECL_NSIDOMEVENTLISTENER
     457             : 
     458             :   bool
     459           2 :   RegisterAndDispatch()
     460             :   {
     461           2 :     AssertIsOnMainThread();
     462             : 
     463           2 :     if (NS_FAILED(mXHR->AddEventListener(mEventType, this, false, false, 2))) {
     464           0 :       NS_WARNING("Failed to add event listener!");
     465           0 :       return false;
     466             :     }
     467             : 
     468           2 :     return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(this));
     469             :   }
     470             : 
     471             : private:
     472           4 :   ~LoadStartDetectionRunnable()
     473           4 :   {
     474           2 :     AssertIsOnMainThread();
     475           6 :     }
     476             : };
     477             : 
     478             : class EventRunnable final : public MainThreadProxyRunnable
     479             :                           , public StructuredCloneHolder
     480             : {
     481             :   nsString mType;
     482             :   nsString mResponseType;
     483             :   JS::Heap<JS::Value> mResponse;
     484             :   XMLHttpRequestStringSnapshot mResponseText;
     485             :   nsString mResponseURL;
     486             :   nsCString mStatusText;
     487             :   uint64_t mLoaded;
     488             :   uint64_t mTotal;
     489             :   uint32_t mEventStreamId;
     490             :   uint32_t mStatus;
     491             :   uint16_t mReadyState;
     492             :   bool mUploadEvent;
     493             :   bool mProgressEvent;
     494             :   bool mLengthComputable;
     495             :   bool mUseCachedArrayBufferResponse;
     496             :   nsresult mResponseTextResult;
     497             :   nsresult mStatusResult;
     498             :   nsresult mResponseResult;
     499             :   // mScopeObj is used in PreDispatch only.  We init it in our constructor, and
     500             :   // reset() in PreDispatch, to ensure that it's not still linked into the
     501             :   // runtime once we go off-thread.
     502             :   JS::PersistentRooted<JSObject*> mScopeObj;
     503             : 
     504             : public:
     505           8 :   EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType,
     506             :                 bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal,
     507             :                 JS::Handle<JSObject*> aScopeObj)
     508           8 :   : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
     509             :     StructuredCloneHolder(CloningSupported, TransferringNotSupported,
     510             :                           StructuredCloneScope::SameProcessDifferentThread),
     511          16 :     mType(aType), mResponse(JS::UndefinedValue()), mLoaded(aLoaded),
     512           8 :     mTotal(aTotal), mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0),
     513             :     mReadyState(0), mUploadEvent(aUploadEvent), mProgressEvent(true),
     514             :     mLengthComputable(aLengthComputable), mUseCachedArrayBufferResponse(false),
     515             :     mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK),
     516          32 :     mScopeObj(RootingCx(), aScopeObj)
     517           8 :   { }
     518             : 
     519           9 :   EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType,
     520             :                 JS::Handle<JSObject*> aScopeObj)
     521           9 :   : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
     522             :     StructuredCloneHolder(CloningSupported, TransferringNotSupported,
     523             :                           StructuredCloneScope::SameProcessDifferentThread),
     524          18 :     mType(aType), mResponse(JS::UndefinedValue()), mLoaded(0), mTotal(0),
     525           9 :     mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
     526             :     mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0),
     527             :     mUseCachedArrayBufferResponse(false), mResponseTextResult(NS_OK),
     528             :     mStatusResult(NS_OK), mResponseResult(NS_OK),
     529          36 :     mScopeObj(RootingCx(), aScopeObj)
     530           9 :   { }
     531             : 
     532             : private:
     533          34 :   ~EventRunnable()
     534          51 :   { }
     535             : 
     536             :   virtual bool
     537             :   PreDispatch(WorkerPrivate* /* unused */) override final;
     538             : 
     539             :   virtual bool
     540             :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
     541             : };
     542             : 
     543             : class SyncTeardownRunnable final : public WorkerThreadProxySyncRunnable
     544             : {
     545             : public:
     546           0 :   SyncTeardownRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
     547           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
     548           0 :   { }
     549             : 
     550             : private:
     551           0 :   ~SyncTeardownRunnable()
     552           0 :   { }
     553             : 
     554             :   virtual void
     555           0 :   RunOnMainThread(ErrorResult& aRv) override
     556             :   {
     557           0 :     mProxy->Teardown(/* aSendUnpin */ true);
     558           0 :     MOZ_ASSERT(!mProxy->mSyncLoopTarget);
     559           0 :   }
     560             : };
     561             : 
     562             : class SetBackgroundRequestRunnable final :
     563             :   public WorkerThreadProxySyncRunnable
     564             : {
     565             :   bool mValue;
     566             : 
     567             : public:
     568           0 :   SetBackgroundRequestRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     569             :                                bool aValue)
     570           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
     571           0 :   , mValue(aValue)
     572           0 :   { }
     573             : 
     574             : private:
     575           0 :   ~SetBackgroundRequestRunnable()
     576           0 :   { }
     577             : 
     578             :   virtual void
     579           0 :   RunOnMainThread(ErrorResult& aRv) override
     580             :   {
     581           0 :     mProxy->mXHR->SetMozBackgroundRequest(mValue, aRv);
     582           0 :   }
     583             : };
     584             : 
     585             : class SetWithCredentialsRunnable final :
     586             :   public WorkerThreadProxySyncRunnable
     587             : {
     588             :   bool mValue;
     589             : 
     590             : public:
     591           0 :   SetWithCredentialsRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     592             :                              bool aValue)
     593           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
     594           0 :   , mValue(aValue)
     595           0 :   { }
     596             : 
     597             : private:
     598           0 :   ~SetWithCredentialsRunnable()
     599           0 :   { }
     600             : 
     601             :   virtual void
     602           0 :   RunOnMainThread(ErrorResult& aRv) override
     603             :   {
     604           0 :     mProxy->mXHR->SetWithCredentials(mValue, aRv);
     605           0 :   }
     606             : };
     607             : 
     608             : class SetResponseTypeRunnable final : public WorkerThreadProxySyncRunnable
     609             : {
     610             :   XMLHttpRequestResponseType mResponseType;
     611             : 
     612             : public:
     613           3 :   SetResponseTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     614             :                           XMLHttpRequestResponseType aResponseType)
     615           3 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
     616           3 :     mResponseType(aResponseType)
     617           3 :   { }
     618             : 
     619             :   XMLHttpRequestResponseType
     620           2 :   ResponseType()
     621             :   {
     622           2 :     return mResponseType;
     623             :   }
     624             : 
     625             : private:
     626           4 :   ~SetResponseTypeRunnable()
     627           6 :   { }
     628             : 
     629             :   virtual void
     630           2 :   RunOnMainThread(ErrorResult& aRv) override
     631             :   {
     632           2 :     mProxy->mXHR->SetResponseType(mResponseType, aRv);
     633           2 :     if (!aRv.Failed()) {
     634           2 :       mResponseType = mProxy->mXHR->ResponseType();
     635             :     }
     636           2 :   }
     637             : };
     638             : 
     639             : class SetTimeoutRunnable final : public WorkerThreadProxySyncRunnable
     640             : {
     641             :   uint32_t mTimeout;
     642             : 
     643             : public:
     644           0 :   SetTimeoutRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     645             :                      uint32_t aTimeout)
     646           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
     647           0 :     mTimeout(aTimeout)
     648           0 :   { }
     649             : 
     650             : private:
     651           0 :   ~SetTimeoutRunnable()
     652           0 :   { }
     653             : 
     654             :   virtual void
     655           0 :   RunOnMainThread(ErrorResult& aRv) override
     656             :   {
     657           0 :     mProxy->mXHR->SetTimeout(mTimeout, aRv);
     658           0 :   }
     659             : };
     660             : 
     661             : class AbortRunnable final : public WorkerThreadProxySyncRunnable
     662             : {
     663             : public:
     664           0 :   AbortRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
     665           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
     666           0 :   { }
     667             : 
     668             : private:
     669           0 :   ~AbortRunnable()
     670           0 :   { }
     671             : 
     672             :   virtual void
     673             :   RunOnMainThread(ErrorResult& aRv) override;
     674             : };
     675             : 
     676             : class GetAllResponseHeadersRunnable final :
     677             :   public WorkerThreadProxySyncRunnable
     678             : {
     679             :   nsCString& mResponseHeaders;
     680             : 
     681             : public:
     682           0 :   GetAllResponseHeadersRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     683             :                                 nsCString& aResponseHeaders)
     684           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
     685           0 :     mResponseHeaders(aResponseHeaders)
     686           0 :   { }
     687             : 
     688             : private:
     689           0 :   ~GetAllResponseHeadersRunnable()
     690           0 :   { }
     691             : 
     692             :   virtual void
     693           0 :   RunOnMainThread(ErrorResult& aRv) override
     694             :   {
     695           0 :     mProxy->mXHR->GetAllResponseHeaders(mResponseHeaders, aRv);
     696           0 :   }
     697             : };
     698             : 
     699             : class GetResponseHeaderRunnable final : public WorkerThreadProxySyncRunnable
     700             : {
     701             :   const nsCString mHeader;
     702             :   nsCString& mValue;
     703             : 
     704             : public:
     705           0 :   GetResponseHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     706             :                             const nsACString& aHeader, nsCString& aValue)
     707           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
     708             :     mHeader(aHeader),
     709           0 :     mValue(aValue)
     710           0 :   { }
     711             : 
     712             : private:
     713           0 :   ~GetResponseHeaderRunnable()
     714           0 :   { }
     715             : 
     716             :   virtual void
     717           0 :   RunOnMainThread(ErrorResult& aRv) override
     718             :   {
     719           0 :     mProxy->mXHR->GetResponseHeader(mHeader, mValue, aRv);
     720           0 :   }
     721             : };
     722             : 
     723             : class OpenRunnable final : public WorkerThreadProxySyncRunnable
     724             : {
     725             :   nsCString mMethod;
     726             :   nsString mURL;
     727             :   Optional<nsAString> mUser;
     728             :   nsString mUserStr;
     729             :   Optional<nsAString> mPassword;
     730             :   nsString mPasswordStr;
     731             :   bool mBackgroundRequest;
     732             :   bool mWithCredentials;
     733             :   uint32_t mTimeout;
     734             :   XMLHttpRequestResponseType mResponseType;
     735             : 
     736             : public:
     737           3 :   OpenRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     738             :                const nsACString& aMethod, const nsAString& aURL,
     739             :                const Optional<nsAString>& aUser,
     740             :                const Optional<nsAString>& aPassword,
     741             :                bool aBackgroundRequest, bool aWithCredentials,
     742             :                uint32_t aTimeout, XMLHttpRequestResponseType aResponseType)
     743           3 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
     744             :     mMethod(aMethod),
     745             :     mURL(aURL), mBackgroundRequest(aBackgroundRequest),
     746             :     mWithCredentials(aWithCredentials), mTimeout(aTimeout),
     747           3 :     mResponseType(aResponseType)
     748             :   {
     749           3 :     if (aUser.WasPassed()) {
     750           3 :       mUserStr = aUser.Value();
     751           3 :       mUser = &mUserStr;
     752             :     }
     753           3 :     if (aPassword.WasPassed()) {
     754           3 :       mPasswordStr = aPassword.Value();
     755           3 :       mPassword = &mPasswordStr;
     756             :     }
     757           3 :   }
     758             : 
     759             : private:
     760           6 :   ~OpenRunnable()
     761           9 :   { }
     762             : 
     763             :   virtual void
     764           3 :   RunOnMainThread(ErrorResult& aRv) override
     765             :   {
     766           3 :     WorkerPrivate* oldWorker = mProxy->mWorkerPrivate;
     767           3 :     mProxy->mWorkerPrivate = mWorkerPrivate;
     768             : 
     769           3 :     aRv = MainThreadRunInternal();
     770             : 
     771           3 :     mProxy->mWorkerPrivate = oldWorker;
     772           3 :   }
     773             : 
     774             :   nsresult
     775             :   MainThreadRunInternal();
     776             : };
     777             : 
     778             : class SetRequestHeaderRunnable final : public WorkerThreadProxySyncRunnable
     779             : {
     780             :   nsCString mHeader;
     781             :   nsCString mValue;
     782             : 
     783             : public:
     784           0 :   SetRequestHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     785             :                            const nsACString& aHeader, const nsACString& aValue)
     786           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
     787             :     mHeader(aHeader),
     788           0 :     mValue(aValue)
     789           0 :   { }
     790             : 
     791             : private:
     792           0 :   ~SetRequestHeaderRunnable()
     793           0 :   { }
     794             : 
     795             :   virtual void
     796           0 :   RunOnMainThread(ErrorResult& aRv) override
     797             :   {
     798           0 :     mProxy->mXHR->SetRequestHeader(mHeader, mValue, aRv);
     799           0 :   }
     800             : };
     801             : 
     802             : class OverrideMimeTypeRunnable final : public WorkerThreadProxySyncRunnable
     803             : {
     804             :   nsString mMimeType;
     805             : 
     806             : public:
     807           0 :   OverrideMimeTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
     808             :                            const nsAString& aMimeType)
     809           0 :   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
     810           0 :     mMimeType(aMimeType)
     811           0 :   { }
     812             : 
     813             : private:
     814           0 :   ~OverrideMimeTypeRunnable()
     815           0 :   { }
     816             : 
     817             :   virtual void
     818           0 :   RunOnMainThread(ErrorResult& aRv) override
     819             :   {
     820           0 :     mProxy->mXHR->OverrideMimeType(mMimeType, aRv);
     821           0 :   }
     822             : };
     823             : 
     824             : class AutoUnpinXHR
     825             : {
     826             :   XMLHttpRequestWorker* mXMLHttpRequestPrivate;
     827             : 
     828             : public:
     829           2 :   explicit AutoUnpinXHR(XMLHttpRequestWorker* aXMLHttpRequestPrivate)
     830           2 :   : mXMLHttpRequestPrivate(aXMLHttpRequestPrivate)
     831             :   {
     832           2 :     MOZ_ASSERT(aXMLHttpRequestPrivate);
     833           2 :   }
     834             : 
     835           2 :   ~AutoUnpinXHR()
     836           2 :   {
     837           2 :     if (mXMLHttpRequestPrivate) {
     838           0 :       mXMLHttpRequestPrivate->Unpin();
     839             :     }
     840           2 :   }
     841             : 
     842           2 :   void Clear()
     843             :   {
     844           2 :     mXMLHttpRequestPrivate = nullptr;
     845           2 :   }
     846             : };
     847             : 
     848             : } // namespace
     849             : 
     850             : bool
     851           3 : Proxy::Init()
     852             : {
     853           3 :   AssertIsOnMainThread();
     854           3 :   MOZ_ASSERT(mWorkerPrivate);
     855             : 
     856           3 :   if (mXHR) {
     857           0 :     return true;
     858             :   }
     859             : 
     860           3 :   nsPIDOMWindowInner* ownerWindow = mWorkerPrivate->GetWindow();
     861           3 :   if (ownerWindow && !ownerWindow->IsCurrentInnerWindow()) {
     862           0 :     NS_WARNING("Window has navigated, cannot create XHR here.");
     863           0 :     return false;
     864             :   }
     865             : 
     866           6 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(ownerWindow);
     867             : 
     868           3 :   mXHR = new XMLHttpRequestMainThread();
     869           6 :   mXHR->Construct(mWorkerPrivate->GetPrincipal(), global,
     870           3 :                   mWorkerPrivate->GetBaseURI(),
     871           6 :                   mWorkerPrivate->GetLoadGroup());
     872             : 
     873           3 :   mXHR->SetParameters(mMozAnon, mMozSystem);
     874             : 
     875           6 :   ErrorResult rv;
     876           3 :   mXHRUpload = mXHR->GetUpload(rv);
     877           3 :   if (NS_WARN_IF(rv.Failed())) {
     878           0 :     mXHR = nullptr;
     879           0 :     return false;
     880             :   }
     881             : 
     882           3 :   if (!AddRemoveEventListeners(false, true)) {
     883           0 :     mXHR = nullptr;
     884           0 :     mXHRUpload = nullptr;
     885           0 :     return false;
     886             :   }
     887             : 
     888           3 :   return true;
     889             : }
     890             : 
     891             : void
     892           0 : Proxy::Teardown(bool aSendUnpin)
     893             : {
     894           0 :   AssertIsOnMainThread();
     895             : 
     896           0 :   if (mXHR) {
     897           0 :     Reset();
     898             : 
     899             :     // NB: We are intentionally dropping events coming from xhr.abort on the
     900             :     // floor.
     901           0 :     AddRemoveEventListeners(false, false);
     902             : 
     903           0 :     ErrorResult rv;
     904           0 :     mXHR->Abort(rv);
     905           0 :     if (NS_WARN_IF(rv.Failed())) {
     906           0 :       rv.SuppressException();
     907             :     }
     908             : 
     909           0 :     if (mOutstandingSendCount) {
     910           0 :       if (aSendUnpin) {
     911             :         RefPtr<XHRUnpinRunnable> runnable =
     912           0 :           new XHRUnpinRunnable(mWorkerPrivate, mXMLHttpRequestPrivate);
     913           0 :         if (!runnable->Dispatch()) {
     914           0 :           MOZ_CRASH("We're going to hang at shutdown anyways.");
     915             :         }
     916             :       }
     917             : 
     918           0 :       if (mSyncLoopTarget) {
     919             :         // We have an unclosed sync loop.  Fix that now.
     920             :         RefPtr<MainThreadStopSyncLoopRunnable> runnable =
     921             :           new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
     922           0 :                                              mSyncLoopTarget.forget(),
     923           0 :                                              false);
     924           0 :         if (!runnable->Dispatch()) {
     925           0 :           MOZ_CRASH("We're going to hang at shutdown anyways.");
     926             :         }
     927             :       }
     928             : 
     929           0 :       mOutstandingSendCount = 0;
     930             :     }
     931             : 
     932           0 :     mWorkerPrivate = nullptr;
     933           0 :     mXHRUpload = nullptr;
     934           0 :     mXHR = nullptr;
     935             :   }
     936             : 
     937           0 :   MOZ_ASSERT(!mWorkerPrivate);
     938           0 :   MOZ_ASSERT(!mSyncLoopTarget);
     939           0 : }
     940             : 
     941             : bool
     942           7 : Proxy::AddRemoveEventListeners(bool aUpload, bool aAdd)
     943             : {
     944           7 :   AssertIsOnMainThread();
     945             : 
     946           7 :   NS_ASSERTION(!aUpload ||
     947             :                (mUploadEventListenersAttached && !aAdd) ||
     948             :                (!mUploadEventListenersAttached && aAdd),
     949             :                "Messed up logic for upload listeners!");
     950             : 
     951             :   nsCOMPtr<nsIDOMEventTarget> target =
     952             :     aUpload ?
     953           4 :     do_QueryInterface(mXHRUpload) :
     954          18 :     do_QueryInterface(static_cast<nsIXMLHttpRequest*>(mXHR.get()));
     955           7 :   NS_ASSERTION(target, "This should never fail!");
     956             : 
     957           7 :   uint32_t lastEventType = aUpload ? STRING_LAST_EVENTTARGET : STRING_LAST_XHR;
     958             : 
     959          14 :   nsAutoString eventType;
     960          55 :   for (uint32_t index = 0; index <= lastEventType; index++) {
     961          48 :     eventType = NS_ConvertASCIItoUTF16(sEventStrings[index]);
     962          48 :     if (aAdd) {
     963          36 :       if (NS_FAILED(target->AddEventListener(eventType, this, false))) {
     964           0 :         return false;
     965             :       }
     966             :     }
     967          12 :     else if (NS_FAILED(target->RemoveEventListener(eventType, this, false))) {
     968           0 :       return false;
     969             :     }
     970             :   }
     971             : 
     972           7 :   if (aUpload) {
     973           4 :     mUploadEventListenersAttached = aAdd;
     974             :   }
     975             : 
     976           7 :   return true;
     977             : }
     978             : 
     979         202 : NS_IMPL_ISUPPORTS(Proxy, nsIDOMEventListener)
     980             : 
     981             : NS_IMETHODIMP
     982          17 : Proxy::HandleEvent(nsIDOMEvent* aEvent)
     983             : {
     984          17 :   AssertIsOnMainThread();
     985             : 
     986          17 :   if (!mWorkerPrivate || !mXMLHttpRequestPrivate) {
     987           0 :     NS_ERROR("Shouldn't get here!");
     988           0 :     return NS_OK;
     989             :   }
     990             : 
     991          34 :   nsString type;
     992          17 :   if (NS_FAILED(aEvent->GetType(type))) {
     993           0 :     NS_WARNING("Failed to get event type!");
     994           0 :     return NS_ERROR_FAILURE;
     995             :   }
     996             : 
     997          34 :   nsCOMPtr<nsIDOMEventTarget> target;
     998          17 :   if (NS_FAILED(aEvent->GetTarget(getter_AddRefs(target)))) {
     999           0 :     NS_WARNING("Failed to get target!");
    1000           0 :     return NS_ERROR_FAILURE;
    1001             :   }
    1002             : 
    1003          34 :   nsCOMPtr<nsIXMLHttpRequestUpload> uploadTarget = do_QueryInterface(target);
    1004          17 :   ProgressEvent* progressEvent = aEvent->InternalDOMEvent()->AsProgressEvent();
    1005             : 
    1006          17 :   if (mInOpen && type.EqualsASCII(sEventStrings[STRING_readystatechange])) {
    1007           3 :     uint16_t readyState = 0;
    1008           6 :     if (NS_SUCCEEDED(mXHR->GetReadyState(&readyState)) &&
    1009           3 :         readyState == nsIXMLHttpRequest::OPENED) {
    1010           3 :       mInnerEventStreamId++;
    1011             :     }
    1012             :   }
    1013             : 
    1014             :   {
    1015          34 :     AutoSafeJSContext cx;
    1016          34 :     JSAutoRequest ar(cx);
    1017             : 
    1018          34 :     JS::Rooted<JS::Value> value(cx);
    1019          17 :     if (!GetOrCreateDOMReflectorNoWrap(cx, mXHR, &value)) {
    1020           0 :       return NS_ERROR_FAILURE;
    1021             :     }
    1022             : 
    1023          34 :     JS::Rooted<JSObject*> scope(cx, &value.toObject());
    1024             : 
    1025          34 :     RefPtr<EventRunnable> runnable;
    1026          17 :     if (progressEvent) {
    1027           8 :       runnable = new EventRunnable(this, !!uploadTarget, type,
    1028           8 :                                    progressEvent->LengthComputable(),
    1029           8 :                                    progressEvent->Loaded(),
    1030           8 :                                    progressEvent->Total(),
    1031          16 :                                    scope);
    1032             :     }
    1033             :     else {
    1034          18 :       runnable = new EventRunnable(this, !!uploadTarget, type, scope);
    1035             :     }
    1036             : 
    1037          17 :     runnable->Dispatch();
    1038             :   }
    1039             : 
    1040          17 :   if (!uploadTarget) {
    1041          17 :     if (type.EqualsASCII(sEventStrings[STRING_loadstart])) {
    1042           2 :       mMainThreadSeenLoadStart = true;
    1043             :     }
    1044          27 :     else if (mMainThreadSeenLoadStart &&
    1045          12 :              type.EqualsASCII(sEventStrings[STRING_loadend])) {
    1046           2 :       mMainThreadSeenLoadStart = false;
    1047             : 
    1048             :       RefPtr<LoadStartDetectionRunnable> runnable =
    1049           4 :         new LoadStartDetectionRunnable(this, mXMLHttpRequestPrivate);
    1050           2 :       if (!runnable->RegisterAndDispatch()) {
    1051           0 :         NS_WARNING("Failed to dispatch LoadStartDetectionRunnable!");
    1052             :       }
    1053             :     }
    1054             :   }
    1055             : 
    1056          17 :   return NS_OK;
    1057             : }
    1058             : 
    1059          58 : NS_IMPL_ISUPPORTS_INHERITED(LoadStartDetectionRunnable, Runnable,
    1060             :                                                         nsIDOMEventListener)
    1061             : 
    1062             : NS_IMETHODIMP
    1063           2 : LoadStartDetectionRunnable::Run()
    1064             : {
    1065           2 :   AssertIsOnMainThread();
    1066             : 
    1067           2 :   if (NS_FAILED(mXHR->RemoveEventListener(mEventType, this, false))) {
    1068           0 :     NS_WARNING("Failed to remove event listener!");
    1069             :   }
    1070             : 
    1071           2 :   if (!mReceivedLoadStart) {
    1072           2 :     if (mProxy->mOutstandingSendCount > 1) {
    1073           0 :       mProxy->mOutstandingSendCount--;
    1074           2 :     } else if (mProxy->mOutstandingSendCount == 1) {
    1075           2 :       mProxy->Reset();
    1076             : 
    1077             :       RefPtr<ProxyCompleteRunnable> runnable =
    1078             :         new ProxyCompleteRunnable(mWorkerPrivate, mProxy,
    1079           6 :                                   mXMLHttpRequestPrivate, mChannelId);
    1080           2 :       if (runnable->Dispatch()) {
    1081           2 :         mProxy->mWorkerPrivate = nullptr;
    1082           2 :         mProxy->mSyncLoopTarget = nullptr;
    1083           2 :         mProxy->mOutstandingSendCount--;
    1084             :       }
    1085             :     }
    1086             :   }
    1087             : 
    1088           2 :   mProxy = nullptr;
    1089           2 :   mXHR = nullptr;
    1090           2 :   mXMLHttpRequestPrivate = nullptr;
    1091           2 :   return NS_OK;
    1092             : }
    1093             : 
    1094             : NS_IMETHODIMP
    1095           0 : LoadStartDetectionRunnable::HandleEvent(nsIDOMEvent* aEvent)
    1096             : {
    1097           0 :   AssertIsOnMainThread();
    1098             : 
    1099             : #ifdef DEBUG
    1100             :   {
    1101           0 :     nsString type;
    1102           0 :     if (NS_SUCCEEDED(aEvent->GetType(type))) {
    1103           0 :       MOZ_ASSERT(type == mEventType);
    1104             :     }
    1105             :     else {
    1106           0 :       NS_WARNING("Failed to get event type!");
    1107             :     }
    1108             :   }
    1109             : #endif
    1110             : 
    1111           0 :   mReceivedLoadStart = true;
    1112           0 :   return NS_OK;
    1113             : }
    1114             : 
    1115             : bool
    1116          17 : EventRunnable::PreDispatch(WorkerPrivate* /* unused */)
    1117             : {
    1118          17 :   AssertIsOnMainThread();
    1119             : 
    1120          34 :   AutoJSAPI jsapi;
    1121          34 :   DebugOnly<bool> ok = jsapi.Init(xpc::NativeGlobal(mScopeObj));
    1122          17 :   MOZ_ASSERT(ok);
    1123          17 :   JSContext* cx = jsapi.cx();
    1124             :   // Now keep the mScopeObj alive for the duration
    1125          34 :   JS::Rooted<JSObject*> scopeObj(cx, mScopeObj);
    1126             :   // And reset mScopeObj now, before we have a chance to run its destructor on
    1127             :   // some background thread.
    1128          17 :   mScopeObj.reset();
    1129             : 
    1130          17 :   RefPtr<XMLHttpRequestMainThread>& xhr = mProxy->mXHR;
    1131          17 :   MOZ_ASSERT(xhr);
    1132             : 
    1133          17 :   if (NS_FAILED(xhr->GetResponseType(mResponseType))) {
    1134           0 :     MOZ_ASSERT(false, "This should never fail!");
    1135             :   }
    1136             : 
    1137          34 :   ErrorResult rv;
    1138          17 :   xhr->GetResponseText(mResponseText, rv);
    1139          17 :   mResponseTextResult = rv.StealNSResult();
    1140             : 
    1141          17 :   if (NS_SUCCEEDED(mResponseTextResult)) {
    1142          17 :     mResponseResult = mResponseTextResult;
    1143          17 :     if (mResponseText.IsVoid()) {
    1144           0 :       mResponse.setNull();
    1145             :     }
    1146             :   }
    1147             :   else {
    1148           0 :     JS::Rooted<JS::Value> response(cx);
    1149           0 :     mResponseResult = xhr->GetResponse(cx, &response);
    1150           0 :     if (NS_SUCCEEDED(mResponseResult)) {
    1151           0 :       if (!response.isGCThing()) {
    1152           0 :         mResponse = response;
    1153             :       } else {
    1154           0 :         bool doClone = true;
    1155           0 :         JS::Rooted<JS::Value> transferable(cx);
    1156           0 :         JS::Rooted<JSObject*> obj(cx, response.isObject() ?
    1157           0 :                                   &response.toObject() : nullptr);
    1158           0 :         if (obj && JS_IsArrayBufferObject(obj)) {
    1159             :           // Use cached response if the arraybuffer has been transfered.
    1160           0 :           if (mProxy->mArrayBufferResponseWasTransferred) {
    1161           0 :             MOZ_ASSERT(JS_IsDetachedArrayBufferObject(obj));
    1162           0 :             mUseCachedArrayBufferResponse = true;
    1163           0 :             doClone = false;
    1164             :           } else {
    1165           0 :             MOZ_ASSERT(!JS_IsDetachedArrayBufferObject(obj));
    1166           0 :             JS::AutoValueArray<1> argv(cx);
    1167           0 :             argv[0].set(response);
    1168           0 :             obj = JS_NewArrayObject(cx, argv);
    1169           0 :             if (obj) {
    1170           0 :               transferable.setObject(*obj);
    1171             :               // Only cache the response when the readyState is DONE.
    1172           0 :               if (xhr->ReadyState() == nsIXMLHttpRequest::DONE) {
    1173           0 :                 mProxy->mArrayBufferResponseWasTransferred = true;
    1174             :               }
    1175             :             } else {
    1176           0 :               mResponseResult = NS_ERROR_OUT_OF_MEMORY;
    1177           0 :               doClone = false;
    1178             :             }
    1179             :           }
    1180             :         }
    1181             : 
    1182           0 :         if (doClone) {
    1183           0 :           Write(cx, response, transferable, JS::CloneDataPolicy(), rv);
    1184           0 :           if (NS_WARN_IF(rv.Failed())) {
    1185           0 :             NS_WARNING("Failed to clone response!");
    1186           0 :             mResponseResult = rv.StealNSResult();
    1187           0 :             mProxy->mArrayBufferResponseWasTransferred = false;
    1188             :           }
    1189             :         }
    1190             :       }
    1191             :     }
    1192             :   }
    1193             : 
    1194          17 :   mStatusResult = xhr->GetStatus(&mStatus);
    1195             : 
    1196          17 :   xhr->GetStatusText(mStatusText, rv);
    1197          17 :   MOZ_ASSERT(!rv.Failed());
    1198             : 
    1199          17 :   mReadyState = xhr->ReadyState();
    1200             : 
    1201          17 :   xhr->GetResponseURL(mResponseURL);
    1202             : 
    1203          34 :   return true;
    1204             : }
    1205             : 
    1206             : bool
    1207          17 : EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
    1208             : {
    1209          17 :   if (mEventStreamId != mProxy->mOuterEventStreamId) {
    1210             :     // Threads raced, this event is now obsolete.
    1211           0 :     return true;
    1212             :   }
    1213             : 
    1214          17 :   if (!mProxy->mXMLHttpRequestPrivate) {
    1215             :     // Object was finalized, bail.
    1216           0 :     return true;
    1217             :   }
    1218             : 
    1219          17 :   if (mType.EqualsASCII(sEventStrings[STRING_loadstart])) {
    1220           2 :     if (mUploadEvent) {
    1221           0 :       mProxy->mSeenUploadLoadStart = true;
    1222             :     }
    1223             :     else {
    1224           2 :       mProxy->mSeenLoadStart = true;
    1225             :     }
    1226             :   }
    1227          15 :   else if (mType.EqualsASCII(sEventStrings[STRING_loadend])) {
    1228           2 :     if (mUploadEvent) {
    1229           0 :       mProxy->mSeenUploadLoadStart = false;
    1230             :     }
    1231             :     else {
    1232           2 :       if (!mProxy->mSeenLoadStart) {
    1233             :         // We've already dispatched premature abort events.
    1234           0 :         return true;
    1235             :       }
    1236           2 :       mProxy->mSeenLoadStart = false;
    1237             :     }
    1238             :   }
    1239          13 :   else if (mType.EqualsASCII(sEventStrings[STRING_abort])) {
    1240           0 :     if ((mUploadEvent && !mProxy->mSeenUploadLoadStart) ||
    1241           0 :         (!mUploadEvent && !mProxy->mSeenLoadStart)) {
    1242             :       // We've already dispatched premature abort events.
    1243           0 :       return true;
    1244             :     }
    1245             :   }
    1246             : 
    1247          17 :   if (mProgressEvent) {
    1248             :     // Cache these for premature abort events.
    1249           8 :     if (mUploadEvent) {
    1250           0 :       mProxy->mLastUploadLengthComputable = mLengthComputable;
    1251           0 :       mProxy->mLastUploadLoaded = mLoaded;
    1252           0 :       mProxy->mLastUploadTotal = mTotal;
    1253             :     }
    1254             :     else {
    1255           8 :       mProxy->mLastLengthComputable = mLengthComputable;
    1256           8 :       mProxy->mLastLoaded = mLoaded;
    1257           8 :       mProxy->mLastTotal = mTotal;
    1258             :     }
    1259             :   }
    1260             : 
    1261          34 :   JS::Rooted<UniquePtr<XMLHttpRequestWorker::StateData>> state(aCx, new XMLHttpRequestWorker::StateData());
    1262             : 
    1263          17 :   state->mResponseTextResult = mResponseTextResult;
    1264             : 
    1265          17 :   state->mResponseText = mResponseText;
    1266             : 
    1267          17 :   if (NS_SUCCEEDED(mResponseTextResult)) {
    1268          17 :     MOZ_ASSERT(mResponse.isUndefined() || mResponse.isNull());
    1269          17 :     state->mResponseResult = mResponseTextResult;
    1270          17 :     state->mResponse = mResponse;
    1271             :   }
    1272             :   else {
    1273           0 :     state->mResponseResult = mResponseResult;
    1274             : 
    1275           0 :     if (NS_SUCCEEDED(mResponseResult)) {
    1276           0 :       if (HasData()) {
    1277           0 :         MOZ_ASSERT(mResponse.isUndefined());
    1278             : 
    1279           0 :         ErrorResult rv;
    1280           0 :         JS::Rooted<JS::Value> response(aCx);
    1281             : 
    1282           0 :         GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
    1283             :         nsCOMPtr<nsIGlobalObject> global =
    1284           0 :           do_QueryInterface(globalObj.GetAsSupports());
    1285             : 
    1286           0 :         Read(global, aCx, &response, rv);
    1287           0 :         if (NS_WARN_IF(rv.Failed())) {
    1288           0 :           rv.SuppressException();
    1289           0 :           return false;
    1290             :         }
    1291             : 
    1292           0 :         state->mResponse = response;
    1293             :       }
    1294             :       else {
    1295           0 :         state->mResponse = mResponse;
    1296             :       }
    1297             :     }
    1298             :   }
    1299             : 
    1300          17 :   state->mStatusResult = mStatusResult;
    1301          17 :   state->mStatus = mStatus;
    1302             : 
    1303          17 :   state->mStatusText = mStatusText;
    1304             : 
    1305          17 :   state->mReadyState = mReadyState;
    1306             : 
    1307          17 :   state->mResponseURL = mResponseURL;
    1308             : 
    1309          17 :   XMLHttpRequestWorker* xhr = mProxy->mXMLHttpRequestPrivate;
    1310          17 :   xhr->UpdateState(*state.get(), mUseCachedArrayBufferResponse);
    1311             : 
    1312          17 :   if (mType.EqualsASCII(sEventStrings[STRING_readystatechange])) {
    1313           9 :     if (mReadyState == 4 && !mUploadEvent && !mProxy->mSeenLoadStart) {
    1314             :       // We've already dispatched premature abort events.
    1315           0 :       return true;
    1316             :     }
    1317             :   }
    1318             : 
    1319          17 :   if (mUploadEvent && !xhr->GetUploadObjectNoCreate()) {
    1320           0 :     return true;
    1321             :   }
    1322             : 
    1323             :   XMLHttpRequestEventTarget* target;
    1324          17 :   if (mUploadEvent) {
    1325           0 :     target = xhr->GetUploadObjectNoCreate();
    1326             :   }
    1327             :   else {
    1328          17 :     target = xhr;
    1329             :   }
    1330             : 
    1331          17 :   MOZ_ASSERT(target);
    1332             : 
    1333          34 :   RefPtr<Event> event;
    1334          17 :   if (mProgressEvent) {
    1335           8 :     ProgressEventInit init;
    1336           8 :     init.mBubbles = false;
    1337           8 :     init.mCancelable = false;
    1338           8 :     init.mLengthComputable = mLengthComputable;
    1339           8 :     init.mLoaded = mLoaded;
    1340           8 :     init.mTotal = mTotal;
    1341             : 
    1342           8 :     event = ProgressEvent::Constructor(target, mType, init);
    1343             :   }
    1344             :   else {
    1345           9 :     event = NS_NewDOMEvent(target, nullptr, nullptr);
    1346             : 
    1347           9 :     if (event) {
    1348           9 :       event->InitEvent(mType, false, false);
    1349             :     }
    1350             :   }
    1351             : 
    1352          17 :   if (!event) {
    1353           0 :     return false;
    1354             :   }
    1355             : 
    1356          17 :   event->SetTrusted(true);
    1357             : 
    1358          17 :   target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
    1359             : 
    1360             :   // After firing the event set mResponse to JSVAL_NULL for chunked response
    1361             :   // types.
    1362          17 :   if (StringBeginsWith(mResponseType, NS_LITERAL_STRING("moz-chunked-"))) {
    1363           0 :     xhr->NullResponseText();
    1364             :   }
    1365             : 
    1366          17 :   return true;
    1367             : }
    1368             : 
    1369             : bool
    1370           7 : WorkerThreadProxySyncRunnable::MainThreadRun()
    1371             : {
    1372           7 :   AssertIsOnMainThread();
    1373             : 
    1374          14 :   nsCOMPtr<nsIEventTarget> tempTarget = mSyncLoopTarget;
    1375             : 
    1376           7 :   mProxy->mSyncEventResponseTarget.swap(tempTarget);
    1377             : 
    1378          14 :   ErrorResult rv;
    1379           7 :   RunOnMainThread(rv);
    1380           7 :   mErrorCode = rv.StealNSResult();
    1381             : 
    1382           7 :   mProxy->mSyncEventResponseTarget.swap(tempTarget);
    1383             : 
    1384          14 :   return true;
    1385             : }
    1386             : 
    1387             : void
    1388           0 : AbortRunnable::RunOnMainThread(ErrorResult& aRv)
    1389             : {
    1390           0 :   mProxy->mInnerEventStreamId++;
    1391             : 
    1392           0 :   WorkerPrivate* oldWorker = mProxy->mWorkerPrivate;
    1393           0 :   mProxy->mWorkerPrivate = mWorkerPrivate;
    1394             : 
    1395           0 :   mProxy->mXHR->Abort(aRv);
    1396             : 
    1397           0 :   mProxy->mWorkerPrivate = oldWorker;
    1398             : 
    1399           0 :   mProxy->Reset();
    1400           0 : }
    1401             : 
    1402             : nsresult
    1403           3 : OpenRunnable::MainThreadRunInternal()
    1404             : {
    1405           3 :   if (!mProxy->Init()) {
    1406           0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    1407             :   }
    1408             : 
    1409             :   nsresult rv;
    1410             : 
    1411           3 :   if (mBackgroundRequest) {
    1412           0 :     rv = mProxy->mXHR->SetMozBackgroundRequest(mBackgroundRequest);
    1413           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1414             :   }
    1415             : 
    1416           3 :   if (mWithCredentials) {
    1417           0 :     rv = mProxy->mXHR->SetWithCredentials(mWithCredentials);
    1418           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1419             :   }
    1420             : 
    1421           3 :   if (mTimeout) {
    1422           0 :     rv = mProxy->mXHR->SetTimeout(mTimeout);
    1423           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1424             :   }
    1425             : 
    1426           3 :   MOZ_ASSERT(!mProxy->mInOpen);
    1427           3 :   mProxy->mInOpen = true;
    1428             : 
    1429           6 :   ErrorResult rv2;
    1430          12 :   mProxy->mXHR->Open(mMethod, mURL, true,
    1431           6 :                      mUser.WasPassed() ? mUser.Value() : NullString(),
    1432           6 :                      mPassword.WasPassed() ? mPassword.Value() : NullString(),
    1433           3 :                      rv2);
    1434             : 
    1435           3 :   MOZ_ASSERT(mProxy->mInOpen);
    1436           3 :   mProxy->mInOpen = false;
    1437             : 
    1438           3 :   if (rv2.Failed()) {
    1439           0 :     return rv2.StealNSResult();
    1440             :   }
    1441             : 
    1442           3 :   mProxy->mXHR->SetResponseType(mResponseType, rv2);
    1443           3 :   if (rv2.Failed()) {
    1444           0 :     return rv2.StealNSResult();
    1445             :   }
    1446             : 
    1447           3 :   return NS_OK;
    1448             : }
    1449             : 
    1450             : void
    1451           2 : SendRunnable::RunOnMainThread(ErrorResult& aRv)
    1452             : {
    1453           4 :   nsCOMPtr<nsIVariant> variant;
    1454             : 
    1455           2 :   if (HasData()) {
    1456           0 :     AutoSafeJSContext cx;
    1457           0 :     JSAutoRequest ar(cx);
    1458             : 
    1459           0 :     nsIXPConnect* xpc = nsContentUtils::XPConnect();
    1460           0 :     MOZ_ASSERT(xpc);
    1461             : 
    1462           0 :     JS::Rooted<JSObject*> globalObject(cx, JS::CurrentGlobalOrNull(cx));
    1463           0 :     if (NS_WARN_IF(!globalObject)) {
    1464           0 :       aRv.Throw(NS_ERROR_FAILURE);
    1465           0 :       return;
    1466             :     }
    1467             : 
    1468           0 :     nsCOMPtr<nsIGlobalObject> parent = xpc::NativeGlobal(globalObject);
    1469           0 :     if (NS_WARN_IF(!parent)) {
    1470           0 :       aRv.Throw(NS_ERROR_FAILURE);
    1471           0 :       return;
    1472             :     }
    1473             : 
    1474           0 :     JS::Rooted<JS::Value> body(cx);
    1475           0 :     Read(parent, cx, &body, aRv);
    1476           0 :     if (NS_WARN_IF(aRv.Failed())) {
    1477           0 :       return;
    1478             :     }
    1479             : 
    1480           0 :     aRv = xpc->JSValToVariant(cx, body, getter_AddRefs(variant));
    1481           0 :     if (NS_WARN_IF(aRv.Failed())) {
    1482           0 :       return;
    1483             :     }
    1484             :   }
    1485             :   else {
    1486           4 :     RefPtr<nsVariant> wvariant = new nsVariant();
    1487             : 
    1488           2 :     if (NS_FAILED(wvariant->SetAsAString(mStringBody))) {
    1489           0 :       MOZ_ASSERT(false, "This should never fail!");
    1490             :     }
    1491             : 
    1492           2 :     variant = wvariant;
    1493             :   }
    1494             : 
    1495             :   // Send() has been already called, reset the proxy.
    1496           2 :   if (mProxy->mWorkerPrivate) {
    1497           0 :     mProxy->Reset();
    1498             :   }
    1499             : 
    1500           2 :   mProxy->mWorkerPrivate = mWorkerPrivate;
    1501             : 
    1502           2 :   MOZ_ASSERT(!mProxy->mSyncLoopTarget);
    1503           2 :   mProxy->mSyncLoopTarget.swap(mSyncLoopTarget);
    1504             : 
    1505           2 :   if (mHasUploadListeners) {
    1506             :     // Send() can be called more than once before failure,
    1507             :     // so don't attach the upload listeners more than once.
    1508           0 :     if (!mProxy->mUploadEventListenersAttached &&
    1509           0 :         !mProxy->AddRemoveEventListeners(true, true)) {
    1510           0 :       MOZ_ASSERT(false, "This should never fail!");
    1511             :     }
    1512             :   }
    1513             : 
    1514           2 :   mProxy->mArrayBufferResponseWasTransferred = false;
    1515             : 
    1516           2 :   mProxy->mInnerChannelId++;
    1517             : 
    1518           2 :   aRv = mProxy->mXHR->Send(variant);
    1519             : 
    1520           2 :   if (!aRv.Failed()) {
    1521           2 :     mProxy->mOutstandingSendCount++;
    1522             : 
    1523           2 :     if (!mHasUploadListeners) {
    1524             :       // Send() can be called more than once before failure,
    1525             :       // so don't attach the upload listeners more than once.
    1526           4 :       if (!mProxy->mUploadEventListenersAttached &&
    1527           2 :           !mProxy->AddRemoveEventListeners(true, true)) {
    1528           0 :         MOZ_ASSERT(false, "This should never fail!");
    1529             :       }
    1530             :     }
    1531             :   }
    1532             : }
    1533             : 
    1534           3 : XMLHttpRequestWorker::XMLHttpRequestWorker(WorkerPrivate* aWorkerPrivate)
    1535             : : mWorkerPrivate(aWorkerPrivate),
    1536             :   mResponseType(XMLHttpRequestResponseType::Text), mTimeout(0),
    1537             :   mRooted(false), mBackgroundRequest(false), mWithCredentials(false),
    1538           3 :   mCanceled(false), mMozAnon(false), mMozSystem(false)
    1539             : {
    1540           3 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1541             : 
    1542           3 :   mozilla::HoldJSObjects(this);
    1543           3 : }
    1544             : 
    1545           0 : XMLHttpRequestWorker::~XMLHttpRequestWorker()
    1546             : {
    1547           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1548             : 
    1549           0 :   ReleaseProxy(XHRIsGoingAway);
    1550             : 
    1551           0 :   MOZ_ASSERT(!mRooted);
    1552             : 
    1553           0 :   mozilla::DropJSObjects(this);
    1554           0 : }
    1555             : 
    1556         246 : NS_IMPL_ADDREF_INHERITED(XMLHttpRequestWorker, XMLHttpRequestEventTarget)
    1557         209 : NS_IMPL_RELEASE_INHERITED(XMLHttpRequestWorker, XMLHttpRequestEventTarget)
    1558             : 
    1559         245 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XMLHttpRequestWorker)
    1560         199 : NS_INTERFACE_MAP_END_INHERITING(XMLHttpRequestEventTarget)
    1561             : 
    1562             : NS_IMPL_CYCLE_COLLECTION_CLASS(XMLHttpRequestWorker)
    1563             : 
    1564           5 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XMLHttpRequestWorker,
    1565             :                                                   XMLHttpRequestEventTarget)
    1566           5 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload)
    1567           5 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1568             : 
    1569           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XMLHttpRequestWorker,
    1570             :                                                 XMLHttpRequestEventTarget)
    1571           0 :   tmp->ReleaseProxy(XHRIsGoingAway);
    1572           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload)
    1573           0 :   tmp->mStateData.mResponse.setUndefined();
    1574           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1575             : 
    1576          10 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(XMLHttpRequestWorker,
    1577             :                                                XMLHttpRequestEventTarget)
    1578          10 :   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStateData.mResponse)
    1579          10 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
    1580             : 
    1581             : /* static */ already_AddRefed<XMLHttpRequest>
    1582           3 : XMLHttpRequestWorker::Construct(const GlobalObject& aGlobal,
    1583             :                                 const MozXMLHttpRequestParameters& aParams,
    1584             :                                 ErrorResult& aRv)
    1585             : {
    1586           3 :   JSContext* cx = aGlobal.Context();
    1587           3 :   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
    1588           3 :   MOZ_ASSERT(workerPrivate);
    1589             : 
    1590           6 :   RefPtr<XMLHttpRequestWorker> xhr = new XMLHttpRequestWorker(workerPrivate);
    1591             : 
    1592           3 :   if (workerPrivate->XHRParamsAllowed()) {
    1593           3 :     if (aParams.mMozSystem)
    1594           0 :       xhr->mMozAnon = true;
    1595             :     else
    1596           3 :       xhr->mMozAnon = aParams.mMozAnon;
    1597           3 :     xhr->mMozSystem = aParams.mMozSystem;
    1598             :   }
    1599             : 
    1600           6 :   return xhr.forget();
    1601             : }
    1602             : 
    1603             : void
    1604           0 : XMLHttpRequestWorker::ReleaseProxy(ReleaseType aType)
    1605             : {
    1606             :   // Can't assert that we're on the worker thread here because mWorkerPrivate
    1607             :   // may be gone.
    1608             : 
    1609           0 :   if (mProxy) {
    1610           0 :     if (aType == XHRIsGoingAway) {
    1611             :       // We're in a GC finalizer, so we can't do a sync call here (and we don't
    1612             :       // need to).
    1613             :       RefPtr<AsyncTeardownRunnable> runnable =
    1614           0 :         new AsyncTeardownRunnable(mProxy);
    1615           0 :       mProxy = nullptr;
    1616             : 
    1617           0 :       if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) {
    1618           0 :         NS_ERROR("Failed to dispatch teardown runnable!");
    1619             :       }
    1620             :     } else {
    1621             :       // This isn't necessary if the worker is going away or the XHR is going
    1622             :       // away.
    1623           0 :       if (aType == Default) {
    1624             :         // Don't let any more events run.
    1625           0 :         mProxy->mOuterEventStreamId++;
    1626             :       }
    1627             : 
    1628             :       // We need to make a sync call here.
    1629             :       RefPtr<SyncTeardownRunnable> runnable =
    1630           0 :         new SyncTeardownRunnable(mWorkerPrivate, mProxy);
    1631           0 :       mProxy = nullptr;
    1632             : 
    1633           0 :       IgnoredErrorResult forAssertionsOnly;
    1634             :       // This runnable _must_ be executed.
    1635           0 :       runnable->Dispatch(Dead, forAssertionsOnly);
    1636           0 :       MOZ_DIAGNOSTIC_ASSERT(!forAssertionsOnly.Failed());
    1637             :     }
    1638             :   }
    1639           0 : }
    1640             : 
    1641             : void
    1642           2 : XMLHttpRequestWorker::MaybePin(ErrorResult& aRv)
    1643             : {
    1644           2 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1645             : 
    1646           2 :   if (mRooted) {
    1647           0 :     return;
    1648             :   }
    1649             : 
    1650           2 :   if (!HoldWorker(mWorkerPrivate, Canceling)) {
    1651           0 :     aRv.Throw(NS_ERROR_FAILURE);
    1652           0 :     return;
    1653             :   }
    1654             : 
    1655           2 :   NS_ADDREF_THIS();
    1656             : 
    1657           2 :   mRooted = true;
    1658             : }
    1659             : 
    1660             : void
    1661           0 : XMLHttpRequestWorker::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv)
    1662             : {
    1663           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1664           0 :   MOZ_ASSERT(mProxy);
    1665             : 
    1666             :   // Only send readystatechange event when state changed.
    1667           0 :   bool isStateChanged = false;
    1668           0 :   if ((mStateData.mReadyState == 1 && mStateData.mFlagSend) ||
    1669           0 :       mStateData.mReadyState == 2 ||
    1670           0 :       mStateData.mReadyState == 3) {
    1671           0 :     isStateChanged = true;
    1672           0 :     mStateData.mReadyState = 4;
    1673             :   }
    1674             : 
    1675           0 :   if (mProxy->mSeenUploadLoadStart) {
    1676           0 :     MOZ_ASSERT(mUpload);
    1677             : 
    1678           0 :     DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("abort"), true,
    1679           0 :                                 aRv);
    1680           0 :     if (aRv.Failed()) {
    1681           0 :       return;
    1682             :     }
    1683             : 
    1684           0 :     DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("loadend"), true,
    1685           0 :                                 aRv);
    1686           0 :     if (aRv.Failed()) {
    1687           0 :       return;
    1688             :     }
    1689             : 
    1690           0 :     mProxy->mSeenUploadLoadStart = false;
    1691             :   }
    1692             : 
    1693           0 :   if (mProxy->mSeenLoadStart) {
    1694           0 :     if (isStateChanged) {
    1695           0 :       DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("readystatechange"),
    1696           0 :                                   false, aRv);
    1697           0 :       if (aRv.Failed()) {
    1698           0 :         return;
    1699             :       }
    1700             :     }
    1701             : 
    1702           0 :     DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("abort"), false, aRv);
    1703           0 :     if (aRv.Failed()) {
    1704           0 :       return;
    1705             :     }
    1706             : 
    1707           0 :     DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("loadend"), false,
    1708           0 :                                 aRv);
    1709           0 :     if (aRv.Failed()) {
    1710           0 :       return;
    1711             :     }
    1712             : 
    1713           0 :     mProxy->mSeenLoadStart = false;
    1714             :   }
    1715             : }
    1716             : 
    1717             : void
    1718           0 : XMLHttpRequestWorker::DispatchPrematureAbortEvent(EventTarget* aTarget,
    1719             :                                                   const nsAString& aEventType,
    1720             :                                                   bool aUploadTarget,
    1721             :                                                   ErrorResult& aRv)
    1722             : {
    1723           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1724           0 :   MOZ_ASSERT(aTarget);
    1725             : 
    1726           0 :   if (!mProxy) {
    1727           0 :     aRv.Throw(NS_ERROR_FAILURE);
    1728           0 :     return;
    1729             :   }
    1730             : 
    1731           0 :   RefPtr<Event> event;
    1732           0 :   if (aEventType.EqualsLiteral("readystatechange")) {
    1733           0 :     event = NS_NewDOMEvent(aTarget, nullptr, nullptr);
    1734           0 :     event->InitEvent(aEventType, false, false);
    1735             :   }
    1736             :   else {
    1737           0 :     ProgressEventInit init;
    1738           0 :     init.mBubbles = false;
    1739           0 :     init.mCancelable = false;
    1740           0 :     if (aUploadTarget) {
    1741           0 :       init.mLengthComputable = mProxy->mLastUploadLengthComputable;
    1742           0 :       init.mLoaded = mProxy->mLastUploadLoaded;
    1743           0 :       init.mTotal = mProxy->mLastUploadTotal;
    1744             :     }
    1745             :     else {
    1746           0 :       init.mLengthComputable = mProxy->mLastLengthComputable;
    1747           0 :       init.mLoaded = mProxy->mLastLoaded;
    1748           0 :       init.mTotal = mProxy->mLastTotal;
    1749             :     }
    1750           0 :     event = ProgressEvent::Constructor(aTarget, aEventType, init);
    1751             :   }
    1752             : 
    1753           0 :   if (!event) {
    1754           0 :     aRv.Throw(NS_ERROR_FAILURE);
    1755           0 :     return;
    1756             :   }
    1757             : 
    1758           0 :   event->SetTrusted(true);
    1759             : 
    1760           0 :   aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
    1761             : }
    1762             : 
    1763             : void
    1764           2 : XMLHttpRequestWorker::Unpin()
    1765             : {
    1766           2 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1767             : 
    1768           2 :   MOZ_ASSERT(mRooted, "Mismatched calls to Unpin!");
    1769             : 
    1770           2 :   ReleaseWorker();
    1771             : 
    1772           2 :   mRooted = false;
    1773             : 
    1774           2 :   NS_RELEASE_THIS();
    1775           2 : }
    1776             : 
    1777             : void
    1778           2 : XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable,
    1779             :                                    ErrorResult& aRv)
    1780             : {
    1781           2 :   MOZ_ASSERT(aRunnable);
    1782           2 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1783             : 
    1784             :   // No send() calls when open is running.
    1785           2 :   if (mProxy->mOpenCount) {
    1786           0 :     aRv.Throw(NS_ERROR_FAILURE);
    1787           0 :     return;
    1788             :   }
    1789             : 
    1790           2 :   bool hasUploadListeners = mUpload ? mUpload->HasListeners() : false;
    1791             : 
    1792           2 :   MaybePin(aRv);
    1793           2 :   if (aRv.Failed()) {
    1794           0 :     return;
    1795             :   }
    1796             : 
    1797           4 :   AutoUnpinXHR autoUnpin(this);
    1798           4 :   Maybe<AutoSyncLoopHolder> autoSyncLoop;
    1799             : 
    1800           4 :   nsCOMPtr<nsIEventTarget> syncLoopTarget;
    1801           2 :   bool isSyncXHR = mProxy->mIsSyncXHR;
    1802           2 :   if (isSyncXHR) {
    1803           2 :     autoSyncLoop.emplace(mWorkerPrivate, Terminating);
    1804           2 :     syncLoopTarget = autoSyncLoop->GetEventTarget();
    1805           2 :     if (!syncLoopTarget) {
    1806           0 :       aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    1807           0 :       return;
    1808             :     }
    1809             :   }
    1810             : 
    1811           2 :   mProxy->mOuterChannelId++;
    1812             : 
    1813           2 :   aRunnable->SetSyncLoopTarget(syncLoopTarget);
    1814           2 :   aRunnable->SetHaveUploadListeners(hasUploadListeners);
    1815             : 
    1816           2 :   mStateData.mFlagSend = true;
    1817             : 
    1818           2 :   aRunnable->Dispatch(Terminating, aRv);
    1819           2 :   if (aRv.Failed()) {
    1820             :     // Dispatch() may have spun the event loop and we may have already unrooted.
    1821             :     // If so we don't want autoUnpin to try again.
    1822           0 :     if (!mRooted) {
    1823           0 :       autoUnpin.Clear();
    1824             :     }
    1825           0 :     return;
    1826             :   }
    1827             : 
    1828           2 :   if (!isSyncXHR)  {
    1829           0 :     autoUnpin.Clear();
    1830           0 :     MOZ_ASSERT(!autoSyncLoop);
    1831           0 :     return;
    1832             :   }
    1833             : 
    1834           2 :   autoUnpin.Clear();
    1835             : 
    1836           2 :   bool succeeded = autoSyncLoop->Run();
    1837           2 :   mStateData.mFlagSend = false;
    1838             : 
    1839             :   // Don't clobber an existing exception that we may have thrown on aRv
    1840             :   // already... though can there really be one?  In any case, it seems to me
    1841             :   // that this autoSyncLoop->Run() can never fail, since the StopSyncLoop call
    1842             :   // for it will come from ProxyCompleteRunnable and that always passes true for
    1843             :   // the second arg.
    1844           2 :   if (!succeeded && !aRv.Failed()) {
    1845           0 :     aRv.Throw(NS_ERROR_FAILURE);
    1846             :   }
    1847             : }
    1848             : 
    1849             : bool
    1850           0 : XMLHttpRequestWorker::Notify(Status aStatus)
    1851             : {
    1852           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1853             : 
    1854           0 :   if (aStatus >= Canceling && !mCanceled) {
    1855           0 :     mCanceled = true;
    1856           0 :     ReleaseProxy(WorkerIsGoingAway);
    1857             :   }
    1858             : 
    1859           0 :   return true;
    1860             : }
    1861             : 
    1862             : void
    1863           3 : XMLHttpRequestWorker::Open(const nsACString& aMethod,
    1864             :                            const nsAString& aUrl, bool aAsync,
    1865             :                            const Optional<nsAString>& aUser,
    1866             :                            const Optional<nsAString>& aPassword,
    1867             :                            ErrorResult& aRv)
    1868             : {
    1869           3 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1870             : 
    1871           3 :   if (mCanceled) {
    1872           0 :     aRv.ThrowUncatchableException();
    1873           0 :     return;
    1874             :   }
    1875             : 
    1876           3 :   if (mProxy) {
    1877           0 :     MaybeDispatchPrematureAbortEvents(aRv);
    1878           0 :     if (aRv.Failed()) {
    1879           0 :       return;
    1880             :     }
    1881             :   }
    1882             :   else {
    1883           3 :     mProxy = new Proxy(this, mMozAnon, mMozSystem);
    1884             :   }
    1885             : 
    1886           3 :   mProxy->mOuterEventStreamId++;
    1887             : 
    1888             :   RefPtr<OpenRunnable> runnable =
    1889             :     new OpenRunnable(mWorkerPrivate, mProxy, aMethod, aUrl, aUser, aPassword,
    1890           6 :                      mBackgroundRequest, mWithCredentials,
    1891          15 :                      mTimeout, mResponseType);
    1892             : 
    1893           3 :   ++mProxy->mOpenCount;
    1894           3 :   runnable->Dispatch(Terminating, aRv);
    1895           3 :   if (aRv.Failed()) {
    1896           0 :     if (!--mProxy->mOpenCount) {
    1897           0 :       ReleaseProxy();
    1898             :     }
    1899             : 
    1900           0 :     return;
    1901             :   }
    1902             : 
    1903             :   // We have been released in one of the nested Open() calls.
    1904           3 :   if (!mProxy) {
    1905           0 :     aRv.Throw(NS_ERROR_FAILURE);
    1906           0 :     return;
    1907             :   }
    1908             : 
    1909           3 :   --mProxy->mOpenCount;
    1910           3 :   mProxy->mIsSyncXHR = !aAsync;
    1911             : }
    1912             : 
    1913             : void
    1914           0 : XMLHttpRequestWorker::SetRequestHeader(const nsACString& aHeader,
    1915             :                                        const nsACString& aValue, ErrorResult& aRv)
    1916             : {
    1917           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1918             : 
    1919           0 :   if (mCanceled) {
    1920           0 :     aRv.ThrowUncatchableException();
    1921           0 :     return;
    1922             :   }
    1923             : 
    1924           0 :   if (!mProxy) {
    1925           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    1926           0 :     return;
    1927             :   }
    1928             : 
    1929             :   RefPtr<SetRequestHeaderRunnable> runnable =
    1930           0 :     new SetRequestHeaderRunnable(mWorkerPrivate, mProxy, aHeader, aValue);
    1931           0 :   runnable->Dispatch(Terminating, aRv);
    1932             : }
    1933             : 
    1934             : void
    1935           0 : XMLHttpRequestWorker::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
    1936             : {
    1937           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1938             : 
    1939           0 :   if (mCanceled) {
    1940           0 :     aRv.ThrowUncatchableException();
    1941           0 :     return;
    1942             :   }
    1943             : 
    1944           0 :   mTimeout = aTimeout;
    1945             : 
    1946           0 :   if (!mProxy) {
    1947             :     // Open may not have been called yet, in which case we'll handle the
    1948             :     // timeout in OpenRunnable.
    1949           0 :     return;
    1950             :   }
    1951             : 
    1952             :   RefPtr<SetTimeoutRunnable> runnable =
    1953           0 :     new SetTimeoutRunnable(mWorkerPrivate, mProxy, aTimeout);
    1954           0 :   runnable->Dispatch(Terminating, aRv);
    1955             : }
    1956             : 
    1957             : void
    1958           0 : XMLHttpRequestWorker::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv)
    1959             : {
    1960           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1961             : 
    1962           0 :   if (mCanceled) {
    1963           0 :     aRv.ThrowUncatchableException();
    1964           0 :     return;
    1965             :   }
    1966             : 
    1967           0 :   mWithCredentials = aWithCredentials;
    1968             : 
    1969           0 :   if (!mProxy) {
    1970             :     // Open may not have been called yet, in which case we'll handle the
    1971             :     // credentials in OpenRunnable.
    1972           0 :     return;
    1973             :   }
    1974             : 
    1975             :   RefPtr<SetWithCredentialsRunnable> runnable =
    1976           0 :     new SetWithCredentialsRunnable(mWorkerPrivate, mProxy, aWithCredentials);
    1977           0 :   runnable->Dispatch(Terminating, aRv);
    1978             : }
    1979             : 
    1980             : void
    1981           0 : XMLHttpRequestWorker::SetMozBackgroundRequest(bool aBackgroundRequest,
    1982             :                                               ErrorResult& aRv)
    1983             : {
    1984           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    1985             : 
    1986           0 :   if (mCanceled) {
    1987           0 :     aRv.ThrowUncatchableException();
    1988           0 :     return;
    1989             :   }
    1990             : 
    1991           0 :   mBackgroundRequest = aBackgroundRequest;
    1992             : 
    1993           0 :   if (!mProxy) {
    1994             :     // Open may not have been called yet, in which case we'll handle the
    1995             :     // background request in OpenRunnable.
    1996           0 :     return;
    1997             :   }
    1998             : 
    1999             :   RefPtr<SetBackgroundRequestRunnable> runnable =
    2000             :     new SetBackgroundRequestRunnable(mWorkerPrivate, mProxy,
    2001           0 :                                      aBackgroundRequest);
    2002           0 :   runnable->Dispatch(Terminating, aRv);
    2003             : }
    2004             : 
    2005             : XMLHttpRequestUpload*
    2006           0 : XMLHttpRequestWorker::GetUpload(ErrorResult& aRv)
    2007             : {
    2008           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2009             : 
    2010           0 :   if (mCanceled) {
    2011           0 :     aRv.ThrowUncatchableException();
    2012           0 :     return nullptr;
    2013             :   }
    2014             : 
    2015           0 :   if (!mUpload) {
    2016           0 :     mUpload = new XMLHttpRequestUpload();
    2017             : 
    2018           0 :     if (!mUpload) {
    2019           0 :       aRv.Throw(NS_ERROR_FAILURE);
    2020           0 :       return nullptr;
    2021             :     }
    2022             :   }
    2023             : 
    2024           0 :   return mUpload;
    2025             : }
    2026             : 
    2027             : void
    2028           2 : XMLHttpRequestWorker::Send(JSContext* aCx, ErrorResult& aRv)
    2029             : {
    2030           2 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2031             : 
    2032           2 :   if (mCanceled) {
    2033           0 :     aRv.ThrowUncatchableException();
    2034           0 :     return;
    2035             :   }
    2036             : 
    2037           2 :   if (!mProxy) {
    2038           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2039           0 :     return;
    2040             :   }
    2041             : 
    2042             :   RefPtr<SendRunnable> sendRunnable =
    2043           6 :     new SendRunnable(mWorkerPrivate, mProxy, NullString());
    2044             : 
    2045             :   // Nothing to clone.
    2046           2 :   SendInternal(sendRunnable, aRv);
    2047             : }
    2048             : 
    2049             : void
    2050           0 : XMLHttpRequestWorker::Send(JSContext* aCx, const nsAString& aBody,
    2051             :                            ErrorResult& aRv)
    2052             : {
    2053           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2054             : 
    2055           0 :   if (mCanceled) {
    2056           0 :     aRv.ThrowUncatchableException();
    2057           0 :     return;
    2058             :   }
    2059             : 
    2060           0 :   if (!mProxy) {
    2061           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2062           0 :     return;
    2063             :   }
    2064             : 
    2065             :   RefPtr<SendRunnable> sendRunnable =
    2066           0 :     new SendRunnable(mWorkerPrivate, mProxy, aBody);
    2067             : 
    2068             :   // Nothing to clone.
    2069           0 :   SendInternal(sendRunnable, aRv);
    2070             : }
    2071             : 
    2072             : void
    2073           0 : XMLHttpRequestWorker::Send(JSContext* aCx, JS::Handle<JSObject*> aBody,
    2074             :                            ErrorResult& aRv)
    2075             : {
    2076           0 :   MOZ_ASSERT(aBody);
    2077             : 
    2078           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2079             : 
    2080           0 :   if (mCanceled) {
    2081           0 :     aRv.ThrowUncatchableException();
    2082           0 :     return;
    2083             :   }
    2084             : 
    2085           0 :   if (!mProxy) {
    2086           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2087           0 :     return;
    2088             :   }
    2089             : 
    2090           0 :   JS::Rooted<JS::Value> valToClone(aCx);
    2091           0 :   if (JS_IsArrayBufferObject(aBody) || JS_IsArrayBufferViewObject(aBody)) {
    2092           0 :     valToClone.setObject(*aBody);
    2093             :   }
    2094             :   else {
    2095           0 :     JS::Rooted<JS::Value> obj(aCx, JS::ObjectValue(*aBody));
    2096           0 :     JSString* bodyStr = JS::ToString(aCx, obj);
    2097           0 :     if (!bodyStr) {
    2098           0 :       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    2099           0 :       return;
    2100             :     }
    2101           0 :     valToClone.setString(bodyStr);
    2102             :   }
    2103             : 
    2104             :   RefPtr<SendRunnable> sendRunnable =
    2105           0 :     new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
    2106             : 
    2107           0 :   sendRunnable->Write(aCx, valToClone, aRv);
    2108           0 :   if (NS_WARN_IF(aRv.Failed())) {
    2109           0 :     return;
    2110             :   }
    2111             : 
    2112           0 :   SendInternal(sendRunnable, aRv);
    2113             : }
    2114             : 
    2115             : void
    2116           0 : XMLHttpRequestWorker::Send(JSContext* aCx, Blob& aBody, ErrorResult& aRv)
    2117             : {
    2118           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2119             : 
    2120           0 :   if (mCanceled) {
    2121           0 :     aRv.ThrowUncatchableException();
    2122           0 :     return;
    2123             :   }
    2124             : 
    2125           0 :   if (!mProxy) {
    2126           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2127           0 :     return;
    2128             :   }
    2129             : 
    2130           0 :   JS::Rooted<JS::Value> value(aCx);
    2131           0 :   if (!GetOrCreateDOMReflector(aCx, &aBody, &value)) {
    2132           0 :     aRv.Throw(NS_ERROR_FAILURE);
    2133           0 :     return;
    2134             :   }
    2135             : 
    2136           0 :   RefPtr<BlobImpl> blobImpl = aBody.Impl();
    2137           0 :   MOZ_ASSERT(blobImpl);
    2138             : 
    2139           0 :   aRv = blobImpl->SetMutable(false);
    2140           0 :   if (NS_WARN_IF(aRv.Failed())) {
    2141           0 :     return;
    2142             :   }
    2143             : 
    2144             :   RefPtr<SendRunnable> sendRunnable =
    2145           0 :     new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
    2146             : 
    2147           0 :   sendRunnable->Write(aCx, value, aRv);
    2148           0 :   if (NS_WARN_IF(aRv.Failed())) {
    2149           0 :     return;
    2150             :   }
    2151             : 
    2152           0 :   SendInternal(sendRunnable, aRv);
    2153             : }
    2154             : 
    2155             : void
    2156           0 : XMLHttpRequestWorker::Send(JSContext* aCx, FormData& aBody, ErrorResult& aRv)
    2157             : {
    2158           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2159             : 
    2160           0 :   if (mCanceled) {
    2161           0 :     aRv.ThrowUncatchableException();
    2162           0 :     return;
    2163             :   }
    2164             : 
    2165           0 :   if (!mProxy) {
    2166           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2167           0 :     return;
    2168             :   }
    2169             : 
    2170           0 :   JS::Rooted<JS::Value> value(aCx);
    2171           0 :   if (!GetOrCreateDOMReflector(aCx, &aBody, &value)) {
    2172           0 :     aRv.Throw(NS_ERROR_FAILURE);
    2173           0 :     return;
    2174             :   }
    2175             : 
    2176             :   RefPtr<SendRunnable> sendRunnable =
    2177           0 :     new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
    2178             : 
    2179           0 :   sendRunnable->Write(aCx, value, aRv);
    2180           0 :   if (NS_WARN_IF(aRv.Failed())) {
    2181           0 :     return;
    2182             :   }
    2183             : 
    2184           0 :   SendInternal(sendRunnable, aRv);
    2185             : }
    2186             : 
    2187             : void
    2188           0 : XMLHttpRequestWorker::Send(JSContext* aCx, URLSearchParams& aBody,
    2189             :                            ErrorResult& aRv)
    2190             : {
    2191           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2192             : 
    2193           0 :   if (mCanceled) {
    2194           0 :     aRv.ThrowUncatchableException();
    2195           0 :     return;
    2196             :   }
    2197             : 
    2198           0 :   if (!mProxy) {
    2199           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2200           0 :     return;
    2201             :   }
    2202             : 
    2203           0 :   JS::Rooted<JS::Value> value(aCx);
    2204           0 :   if (!GetOrCreateDOMReflector(aCx, &aBody, &value)) {
    2205           0 :     aRv.Throw(NS_ERROR_FAILURE);
    2206           0 :     return;
    2207             :   }
    2208             : 
    2209             :   RefPtr<SendRunnable> sendRunnable =
    2210           0 :     new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
    2211             : 
    2212           0 :   sendRunnable->Write(aCx, value, aRv);
    2213           0 :   if (NS_WARN_IF(aRv.Failed())) {
    2214           0 :     return;
    2215             :   }
    2216             : 
    2217           0 :   SendInternal(sendRunnable, aRv);
    2218             : }
    2219             : 
    2220             : void
    2221           0 : XMLHttpRequestWorker::Send(JSContext* aCx, const ArrayBuffer& aBody,
    2222             :                            ErrorResult& aRv)
    2223             : {
    2224           0 :   JS::Rooted<JSObject*> obj(mWorkerPrivate->GetJSContext(), aBody.Obj());
    2225           0 :   return Send(aCx, obj, aRv);
    2226             : }
    2227             : 
    2228             : void
    2229           0 : XMLHttpRequestWorker::Send(JSContext* aCx, const ArrayBufferView& aBody,
    2230             :                            ErrorResult& aRv)
    2231             : {
    2232           0 :   if (JS_IsTypedArrayObject(aBody.Obj()) &&
    2233           0 :       JS_GetTypedArraySharedness(aBody.Obj())) {
    2234             :     // Throw if the object is mapping shared memory (must opt in).
    2235           0 :     aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of XMLHttpRequest.send"));
    2236           0 :     return;
    2237             :   }
    2238           0 :   JS::Rooted<JSObject*> obj(aCx, aBody.Obj());
    2239           0 :   return Send(aCx, obj, aRv);
    2240             : }
    2241             : 
    2242             : void
    2243           0 : XMLHttpRequestWorker::Abort(ErrorResult& aRv)
    2244             : {
    2245           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2246             : 
    2247           0 :   if (mCanceled) {
    2248           0 :     aRv.ThrowUncatchableException();
    2249           0 :     return;
    2250             :   }
    2251             : 
    2252           0 :   if (!mProxy) {
    2253           0 :     return;
    2254             :   }
    2255             : 
    2256           0 :   MaybeDispatchPrematureAbortEvents(aRv);
    2257           0 :   if (aRv.Failed()) {
    2258           0 :     return;
    2259             :   }
    2260             : 
    2261           0 :   if (mStateData.mReadyState == 4) {
    2262             :     // No one did anything to us while we fired abort events, so reset our state
    2263             :     // to "unsent"
    2264           0 :     mStateData.mReadyState = 0;
    2265             :   }
    2266             : 
    2267           0 :   mProxy->mOuterEventStreamId++;
    2268             : 
    2269           0 :   RefPtr<AbortRunnable> runnable = new AbortRunnable(mWorkerPrivate, mProxy);
    2270           0 :   runnable->Dispatch(Terminating, aRv);
    2271             : }
    2272             : 
    2273             : void
    2274           0 : XMLHttpRequestWorker::GetResponseHeader(const nsACString& aHeader,
    2275             :                                         nsACString& aResponseHeader, ErrorResult& aRv)
    2276             : {
    2277           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2278             : 
    2279           0 :   if (mCanceled) {
    2280           0 :     aRv.ThrowUncatchableException();
    2281           0 :     return;
    2282             :   }
    2283             : 
    2284           0 :   if (!mProxy) {
    2285           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2286           0 :     return;
    2287             :   }
    2288             : 
    2289           0 :   nsCString responseHeader;
    2290             :   RefPtr<GetResponseHeaderRunnable> runnable =
    2291             :     new GetResponseHeaderRunnable(mWorkerPrivate, mProxy, aHeader,
    2292           0 :                                   responseHeader);
    2293           0 :   runnable->Dispatch(Terminating, aRv);
    2294           0 :   if (aRv.Failed()) {
    2295           0 :     return;
    2296             :   }
    2297           0 :   aResponseHeader = responseHeader;
    2298             : }
    2299             : 
    2300             : void
    2301           0 : XMLHttpRequestWorker::GetAllResponseHeaders(nsACString& aResponseHeaders,
    2302             :                                             ErrorResult& aRv)
    2303             : {
    2304           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2305             : 
    2306           0 :   if (mCanceled) {
    2307           0 :     aRv.ThrowUncatchableException();
    2308           0 :     return;
    2309             :   }
    2310             : 
    2311           0 :   if (!mProxy) {
    2312           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2313           0 :     return;
    2314             :   }
    2315             : 
    2316           0 :   nsCString responseHeaders;
    2317             :   RefPtr<GetAllResponseHeadersRunnable> runnable =
    2318           0 :     new GetAllResponseHeadersRunnable(mWorkerPrivate, mProxy, responseHeaders);
    2319           0 :   runnable->Dispatch(Terminating, aRv);
    2320           0 :   if (aRv.Failed()) {
    2321           0 :     return;
    2322             :   }
    2323             : 
    2324           0 :   aResponseHeaders = responseHeaders;
    2325             : }
    2326             : 
    2327             : void
    2328           0 : XMLHttpRequestWorker::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv)
    2329             : {
    2330           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2331             : 
    2332           0 :   if (mCanceled) {
    2333           0 :     aRv.ThrowUncatchableException();
    2334           0 :     return;
    2335             :   }
    2336             : 
    2337             :   // We're supposed to throw if the state is not OPENED or HEADERS_RECEIVED. We
    2338             :   // can detect OPENED really easily but we can't detect HEADERS_RECEIVED in a
    2339             :   // non-racy way until the XHR state machine actually runs on this thread
    2340             :   // (bug 671047). For now we're going to let this work only if the Send()
    2341             :   // method has not been called, unless the send has been aborted.
    2342           0 :   if (!mProxy || (SendInProgress() &&
    2343           0 :                   (mProxy->mSeenLoadStart ||
    2344           0 :                    mStateData.mReadyState > nsIXMLHttpRequest::OPENED))) {
    2345           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2346           0 :     return;
    2347             :   }
    2348             : 
    2349             :   RefPtr<OverrideMimeTypeRunnable> runnable =
    2350           0 :     new OverrideMimeTypeRunnable(mWorkerPrivate, mProxy, aMimeType);
    2351           0 :   runnable->Dispatch(Terminating, aRv);
    2352             : }
    2353             : 
    2354             : void
    2355           3 : XMLHttpRequestWorker::SetResponseType(XMLHttpRequestResponseType aResponseType,
    2356             :                                       ErrorResult& aRv)
    2357             : {
    2358           3 :   mWorkerPrivate->AssertIsOnWorkerThread();
    2359             : 
    2360           3 :   if (mCanceled) {
    2361           0 :     aRv.ThrowUncatchableException();
    2362           0 :     return;
    2363             :   }
    2364             : 
    2365             :   // "document" is fine for the main thread but not for a worker. Short-circuit
    2366             :   // that here.
    2367           3 :   if (aResponseType == XMLHttpRequestResponseType::Document) {
    2368           0 :     return;
    2369             :   }
    2370             : 
    2371           3 :   if (!mProxy) {
    2372             :     // Open() has not been called yet. We store the responseType and we will use
    2373             :     // it later in Open().
    2374           0 :     mResponseType = aResponseType;
    2375           0 :     return;
    2376             :   }
    2377             : 
    2378           3 :   if (SendInProgress() &&
    2379           0 :       (mProxy->mSeenLoadStart ||
    2380           0 :        mStateData.mReadyState > nsIXMLHttpRequest::OPENED)) {
    2381           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2382           0 :     return;
    2383             :   }
    2384             : 
    2385             :   RefPtr<SetResponseTypeRunnable> runnable =
    2386           8 :     new SetResponseTypeRunnable(mWorkerPrivate, mProxy, aResponseType);
    2387           3 :   runnable->Dispatch(Terminating, aRv);
    2388           2 :   if (aRv.Failed()) {
    2389           0 :     return;
    2390             :   }
    2391             : 
    2392           2 :   mResponseType = runnable->ResponseType();
    2393             : }
    2394             : 
    2395             : void
    2396           0 : XMLHttpRequestWorker::GetResponse(JSContext* /* unused */,
    2397             :                                   JS::MutableHandle<JS::Value> aResponse,
    2398             :                                   ErrorResult& aRv)
    2399             : {
    2400           0 :   if (NS_SUCCEEDED(mStateData.mResponseTextResult) &&
    2401           0 :       mStateData.mResponse.isUndefined()) {
    2402           0 :     MOZ_ASSERT(NS_SUCCEEDED(mStateData.mResponseResult));
    2403             : 
    2404           0 :     if (mStateData.mResponseText.IsEmpty()) {
    2405             :       mStateData.mResponse =
    2406           0 :         JS_GetEmptyStringValue(mWorkerPrivate->GetJSContext());
    2407             :     } else {
    2408           0 :       XMLHttpRequestStringSnapshotReaderHelper helper(mStateData.mResponseText);
    2409             : 
    2410             :       JSString* str =
    2411           0 :         JS_NewUCStringCopyN(mWorkerPrivate->GetJSContext(),
    2412           0 :                             helper.Buffer(), helper.Length());
    2413             : 
    2414           0 :       if (!str) {
    2415           0 :         aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    2416           0 :         return;
    2417             :       }
    2418             : 
    2419           0 :       mStateData.mResponse.setString(str);
    2420             :     }
    2421             :   }
    2422             : 
    2423           0 :   aRv = mStateData.mResponseResult;
    2424           0 :   aResponse.set(mStateData.mResponse);
    2425             : }
    2426             : 
    2427             : void
    2428           2 : XMLHttpRequestWorker::GetResponseText(DOMString& aResponseText, ErrorResult& aRv)
    2429             : {
    2430           2 :   aRv = mStateData.mResponseTextResult;
    2431           2 :   if (aRv.Failed()) {
    2432           0 :     return;
    2433             :   }
    2434             : 
    2435           2 :   if (!mStateData.mResponseText.GetAsString(aResponseText)) {
    2436           0 :     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    2437           0 :     return;
    2438             :   }
    2439             : }
    2440             : 
    2441             : void
    2442          17 : XMLHttpRequestWorker::UpdateState(const StateData& aStateData,
    2443             :                                   bool aUseCachedArrayBufferResponse)
    2444             : {
    2445          17 :   if (aUseCachedArrayBufferResponse) {
    2446           0 :     MOZ_ASSERT(mStateData.mResponse.isObject() &&
    2447             :                JS_IsArrayBufferObject(&mStateData.mResponse.toObject()));
    2448             : 
    2449           0 :     JS::Rooted<JS::Value> response(mWorkerPrivate->GetJSContext(),
    2450           0 :                                    mStateData.mResponse);
    2451           0 :     mStateData = aStateData;
    2452           0 :     mStateData.mResponse = response;
    2453             :   }
    2454             :   else {
    2455          17 :     mStateData = aStateData;
    2456             :   }
    2457             : 
    2458          17 :   XMLHttpRequestBinding::ClearCachedResponseTextValue(this);
    2459          17 : }
    2460             : 
    2461             : } // dom namespace
    2462           9 : } // mozilla namespace

Generated by: LCOV version 1.13