LCOV - code coverage report
Current view: top level - dom/workers - ScriptLoader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 346 958 36.1 %
Date: 2017-07-14 16:53:18 Functions: 40 95 42.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "ScriptLoader.h"
       8             : 
       9             : #include "nsIChannel.h"
      10             : #include "nsIContentPolicy.h"
      11             : #include "nsIContentSecurityPolicy.h"
      12             : #include "nsIDocShell.h"
      13             : #include "nsIDOMDocument.h"
      14             : #include "nsIHttpChannel.h"
      15             : #include "nsIHttpChannelInternal.h"
      16             : #include "nsIInputStreamPump.h"
      17             : #include "nsIIOService.h"
      18             : #include "nsIProtocolHandler.h"
      19             : #include "nsIScriptError.h"
      20             : #include "nsIScriptSecurityManager.h"
      21             : #include "nsIStreamLoader.h"
      22             : #include "nsIStreamListenerTee.h"
      23             : #include "nsIThreadRetargetableRequest.h"
      24             : #include "nsIURI.h"
      25             : 
      26             : #include "jsapi.h"
      27             : #include "jsfriendapi.h"
      28             : #include "nsError.h"
      29             : #include "nsContentPolicyUtils.h"
      30             : #include "nsContentUtils.h"
      31             : #include "nsDocShellCID.h"
      32             : #include "nsISupportsPrimitives.h"
      33             : #include "nsNetUtil.h"
      34             : #include "nsIPipe.h"
      35             : #include "nsIOutputStream.h"
      36             : #include "nsPrintfCString.h"
      37             : #include "nsString.h"
      38             : #include "nsStreamUtils.h"
      39             : #include "nsTArray.h"
      40             : #include "nsThreadUtils.h"
      41             : #include "nsXPCOM.h"
      42             : #include "xpcpublic.h"
      43             : 
      44             : #include "mozilla/Assertions.h"
      45             : #include "mozilla/LoadContext.h"
      46             : #include "mozilla/Maybe.h"
      47             : #include "mozilla/ipc/BackgroundUtils.h"
      48             : #include "mozilla/dom/CacheBinding.h"
      49             : #include "mozilla/dom/cache/CacheTypes.h"
      50             : #include "mozilla/dom/cache/Cache.h"
      51             : #include "mozilla/dom/cache/CacheStorage.h"
      52             : #include "mozilla/dom/ChannelInfo.h"
      53             : #include "mozilla/dom/Exceptions.h"
      54             : #include "mozilla/dom/InternalResponse.h"
      55             : #include "mozilla/dom/nsCSPService.h"
      56             : #include "mozilla/dom/nsCSPUtils.h"
      57             : #include "mozilla/dom/Promise.h"
      58             : #include "mozilla/dom/PromiseNativeHandler.h"
      59             : #include "mozilla/dom/Response.h"
      60             : #include "mozilla/dom/ScriptLoader.h"
      61             : #include "mozilla/dom/ScriptSettings.h"
      62             : #include "mozilla/dom/SRILogHelper.h"
      63             : #include "mozilla/UniquePtr.h"
      64             : #include "Principal.h"
      65             : #include "WorkerHolder.h"
      66             : #include "WorkerPrivate.h"
      67             : #include "WorkerRunnable.h"
      68             : #include "WorkerScope.h"
      69             : 
      70             : #define MAX_CONCURRENT_SCRIPTS 1000
      71             : 
      72             : USING_WORKERS_NAMESPACE
      73             : 
      74             : using namespace mozilla;
      75             : using namespace mozilla::dom;
      76             : using mozilla::dom::cache::Cache;
      77             : using mozilla::dom::cache::CacheStorage;
      78             : using mozilla::ipc::PrincipalInfo;
      79             : 
      80             : namespace {
      81             : 
      82             : nsIURI*
      83           8 : GetBaseURI(bool aIsMainScript, WorkerPrivate* aWorkerPrivate)
      84             : {
      85           8 :   MOZ_ASSERT(aWorkerPrivate);
      86             :   nsIURI* baseURI;
      87           8 :   WorkerPrivate* parentWorker = aWorkerPrivate->GetParent();
      88           8 :   if (aIsMainScript) {
      89           1 :     if (parentWorker) {
      90           0 :       baseURI = parentWorker->GetBaseURI();
      91           0 :       NS_ASSERTION(baseURI, "Should have been set already!");
      92             :     }
      93             :     else {
      94             :       // May be null.
      95           1 :       baseURI = aWorkerPrivate->GetBaseURI();
      96             :     }
      97             :   }
      98             :   else {
      99           7 :     baseURI = aWorkerPrivate->GetBaseURI();
     100           7 :     NS_ASSERTION(baseURI, "Should have been set already!");
     101             :   }
     102             : 
     103           8 :   return baseURI;
     104             : }
     105             : 
     106             : nsresult
     107           8 : ChannelFromScriptURL(nsIPrincipal* principal,
     108             :                      nsIURI* baseURI,
     109             :                      nsIDocument* parentDoc,
     110             :                      nsILoadGroup* loadGroup,
     111             :                      nsIIOService* ios,
     112             :                      nsIScriptSecurityManager* secMan,
     113             :                      const nsAString& aScriptURL,
     114             :                      bool aIsMainScript,
     115             :                      WorkerScriptType aWorkerScriptType,
     116             :                      nsContentPolicyType aMainScriptContentPolicyType,
     117             :                      nsLoadFlags aLoadFlags,
     118             :                      bool aDefaultURIEncoding,
     119             :                      nsIChannel** aChannel)
     120             : {
     121           8 :   AssertIsOnMainThread();
     122             : 
     123             :   nsresult rv;
     124          16 :   nsCOMPtr<nsIURI> uri;
     125             : 
     126           8 :   if (aDefaultURIEncoding) {
     127           7 :     rv = NS_NewURI(getter_AddRefs(uri), aScriptURL, nullptr, baseURI);
     128             :   } else {
     129           2 :     rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
     130             :                                                    aScriptURL, parentDoc,
     131           1 :                                                    baseURI);
     132             :   }
     133             : 
     134           8 :   if (NS_FAILED(rv)) {
     135           0 :     return NS_ERROR_DOM_SYNTAX_ERR;
     136             :   }
     137             : 
     138             :   // If we have the document, use it. Unfortunately, for dedicated workers
     139             :   // 'parentDoc' ends up being the parent document, which is not the document
     140             :   // that we want to use. So make sure to avoid using 'parentDoc' in that
     141             :   // situation.
     142           8 :   if (parentDoc && parentDoc->NodePrincipal() != principal) {
     143           0 :     parentDoc = nullptr;
     144             :   }
     145             : 
     146           8 :   aLoadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
     147           8 :   uint32_t secFlags = aIsMainScript ? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
     148           8 :                                     : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
     149             : 
     150           8 :   if (aWorkerScriptType == DebuggerScript) {
     151             :     // A DebuggerScript needs to be a local resource like chrome: or resource:
     152           0 :     bool isUIResource = false;
     153           0 :     rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE,
     154           0 :                              &isUIResource);
     155           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     156           0 :       return rv;
     157             :     }
     158             : 
     159           0 :     if (!isUIResource) {
     160           0 :       return NS_ERROR_DOM_SECURITY_ERR;
     161             :     }
     162             : 
     163           0 :     secFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
     164             :   }
     165             : 
     166             :   // Note: this is for backwards compatibility and goes against spec.
     167             :   // We should find a better solution.
     168           8 :   bool isData = false;
     169           8 :   if (aIsMainScript && NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData) {
     170           0 :     secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
     171             :   }
     172             : 
     173             :   nsContentPolicyType contentPolicyType =
     174           8 :     aIsMainScript ? aMainScriptContentPolicyType
     175           8 :                   : nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS;
     176             : 
     177          16 :   nsCOMPtr<nsIChannel> channel;
     178             :   // If we have the document, use it. Unfortunately, for dedicated workers
     179             :   // 'parentDoc' ends up being the parent document, which is not the document
     180             :   // that we want to use. So make sure to avoid using 'parentDoc' in that
     181             :   // situation.
     182           8 :   if (parentDoc && parentDoc->NodePrincipal() == principal) {
     183           0 :     rv = NS_NewChannel(getter_AddRefs(channel),
     184             :                        uri,
     185             :                        parentDoc,
     186             :                        secFlags,
     187             :                        contentPolicyType,
     188             :                        loadGroup,
     189             :                        nullptr, // aCallbacks
     190             :                        aLoadFlags,
     191           0 :                        ios);
     192             :   } else {
     193             :     // We must have a loadGroup with a load context for the principal to
     194             :     // traverse the channel correctly.
     195           8 :     MOZ_ASSERT(loadGroup);
     196           8 :     MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadGroup, principal));
     197             : 
     198          16 :     rv = NS_NewChannel(getter_AddRefs(channel),
     199             :                        uri,
     200             :                        principal,
     201             :                        secFlags,
     202             :                        contentPolicyType,
     203             :                        loadGroup,
     204             :                        nullptr, // aCallbacks
     205             :                        aLoadFlags,
     206           8 :                        ios);
     207             :   }
     208             : 
     209           8 :   NS_ENSURE_SUCCESS(rv, rv);
     210             : 
     211          16 :   if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel)) {
     212           0 :     mozilla::net::ReferrerPolicy referrerPolicy = parentDoc ?
     213           0 :       parentDoc->GetReferrerPolicy() : mozilla::net::RP_Unset;
     214           0 :     rv = nsContentUtils::SetFetchReferrerURIWithPolicy(principal, parentDoc,
     215           0 :                                                        httpChannel, referrerPolicy);
     216           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     217           0 :       return rv;
     218             :     }
     219             :   }
     220             : 
     221           8 :   channel.forget(aChannel);
     222           8 :   return rv;
     223             : }
     224             : 
     225             : struct ScriptLoadInfo
     226             : {
     227           8 :   ScriptLoadInfo()
     228           8 :   : mScriptTextBuf(nullptr)
     229             :   , mScriptTextLength(0)
     230             :   , mLoadResult(NS_ERROR_NOT_INITIALIZED)
     231             :   , mLoadingFinished(false)
     232             :   , mExecutionScheduled(false)
     233             :   , mExecutionResult(false)
     234             :   , mCacheStatus(Uncached)
     235           8 :   , mLoadFlags(nsIRequest::LOAD_NORMAL)
     236           8 :   { }
     237             : 
     238           2 :   ~ScriptLoadInfo()
     239           2 :   {
     240           2 :     if (mScriptTextBuf) {
     241           0 :       js_free(mScriptTextBuf);
     242             :     }
     243           2 :   }
     244             : 
     245             :   nsString mURL;
     246             : 
     247             :   // This full URL string is populated only if this object is used in a
     248             :   // ServiceWorker.
     249             :   nsString mFullURL;
     250             : 
     251             :   // This promise is set only when the script is for a ServiceWorker but
     252             :   // it's not in the cache yet. The promise is resolved when the full body is
     253             :   // stored into the cache.  mCachePromise will be set to nullptr after
     254             :   // resolution.
     255             :   RefPtr<Promise> mCachePromise;
     256             : 
     257             :   // The reader stream the cache entry should be filled from, for those cases
     258             :   // when we're going to have an mCachePromise.
     259             :   nsCOMPtr<nsIInputStream> mCacheReadStream;
     260             : 
     261             :   nsCOMPtr<nsIChannel> mChannel;
     262             :   char16_t* mScriptTextBuf;
     263             :   size_t mScriptTextLength;
     264             : 
     265             :   nsresult mLoadResult;
     266             :   bool mLoadingFinished;
     267             :   bool mExecutionScheduled;
     268             :   bool mExecutionResult;
     269             : 
     270             :   enum CacheStatus {
     271             :     // By default a normal script is just loaded from the network. But for
     272             :     // ServiceWorkers, we have to check if the cache contains the script and
     273             :     // load it from the cache.
     274             :     Uncached,
     275             : 
     276             :     WritingToCache,
     277             : 
     278             :     ReadingFromCache,
     279             : 
     280             :     // This script has been loaded from the ServiceWorker cache.
     281             :     Cached,
     282             : 
     283             :     // This script must be stored in the ServiceWorker cache.
     284             :     ToBeCached,
     285             : 
     286             :     // Something went wrong or the worker went away.
     287             :     Cancel
     288             :   };
     289             : 
     290             :   CacheStatus mCacheStatus;
     291             : 
     292             :   nsLoadFlags mLoadFlags;
     293             : 
     294             :   Maybe<bool> mMutedErrorFlag;
     295             : 
     296          19 :   bool Finished() const
     297             :   {
     298          19 :     return mLoadingFinished && !mCachePromise && !mChannel;
     299             :   }
     300             : };
     301             : 
     302             : class ScriptLoaderRunnable;
     303             : 
     304             : class ScriptExecutorRunnable final : public MainThreadWorkerSyncRunnable
     305             : {
     306             :   ScriptLoaderRunnable& mScriptLoader;
     307             :   bool mIsWorkerScript;
     308             :   uint32_t mFirstIndex;
     309             :   uint32_t mLastIndex;
     310             : 
     311             : public:
     312             :   ScriptExecutorRunnable(ScriptLoaderRunnable& aScriptLoader,
     313             :                          nsIEventTarget* aSyncLoopTarget,
     314             :                          bool aIsWorkerScript,
     315             :                          uint32_t aFirstIndex,
     316             :                          uint32_t aLastIndex);
     317             : 
     318             : private:
     319           6 :   ~ScriptExecutorRunnable()
     320           9 :   { }
     321             : 
     322             :   virtual bool
     323             :   IsDebuggerRunnable() const override;
     324             : 
     325             :   virtual bool
     326             :   PreRun(WorkerPrivate* aWorkerPrivate) override;
     327             : 
     328             :   virtual bool
     329             :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
     330             : 
     331             :   virtual void
     332             :   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
     333             :           override;
     334             : 
     335             :   nsresult
     336             :   Cancel() override;
     337             : 
     338             :   void
     339             :   ShutdownScriptLoader(JSContext* aCx,
     340             :                        WorkerPrivate* aWorkerPrivate,
     341             :                        bool aResult,
     342             :                        bool aMutedError);
     343             : 
     344             :   void LogExceptionToConsole(JSContext* aCx,
     345             :                              WorkerPrivate* WorkerPrivate);
     346             : };
     347             : 
     348             : class CacheScriptLoader;
     349             : 
     350             : class CacheCreator final : public PromiseNativeHandler
     351             : {
     352             : public:
     353             :   NS_DECL_ISUPPORTS
     354             : 
     355           0 :   explicit CacheCreator(WorkerPrivate* aWorkerPrivate)
     356           0 :     : mCacheName(aWorkerPrivate->ServiceWorkerCacheName())
     357           0 :     , mOriginAttributes(aWorkerPrivate->GetOriginAttributes())
     358             :   {
     359           0 :     MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
     360           0 :     MOZ_ASSERT(aWorkerPrivate->LoadScriptAsPartOfLoadingServiceWorkerScript());
     361           0 :     AssertIsOnMainThread();
     362           0 :   }
     363             : 
     364             :   void
     365           0 :   AddLoader(CacheScriptLoader* aLoader)
     366             :   {
     367           0 :     AssertIsOnMainThread();
     368           0 :     MOZ_ASSERT(!mCacheStorage);
     369           0 :     mLoaders.AppendElement(aLoader);
     370           0 :   }
     371             : 
     372             :   virtual void
     373             :   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
     374             : 
     375             :   virtual void
     376             :   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
     377             : 
     378             :   // Try to load from cache with aPrincipal used for cache access.
     379             :   nsresult
     380             :   Load(nsIPrincipal* aPrincipal);
     381             : 
     382             :   Cache*
     383           0 :   Cache_() const
     384             :   {
     385           0 :     AssertIsOnMainThread();
     386           0 :     MOZ_ASSERT(mCache);
     387           0 :     return mCache;
     388             :   }
     389             : 
     390             :   nsIGlobalObject*
     391           0 :   Global() const
     392             :   {
     393           0 :     AssertIsOnMainThread();
     394           0 :     MOZ_ASSERT(mSandboxGlobalObject);
     395           0 :     return mSandboxGlobalObject;
     396             :   }
     397             : 
     398             :   void
     399             :   DeleteCache();
     400             : 
     401             : private:
     402           0 :   ~CacheCreator()
     403           0 :   {
     404           0 :   }
     405             : 
     406             :   nsresult
     407             :   CreateCacheStorage(nsIPrincipal* aPrincipal);
     408             : 
     409             :   void
     410             :   FailLoaders(nsresult aRv);
     411             : 
     412             :   RefPtr<Cache> mCache;
     413             :   RefPtr<CacheStorage> mCacheStorage;
     414             :   nsCOMPtr<nsIGlobalObject> mSandboxGlobalObject;
     415             :   nsTArray<RefPtr<CacheScriptLoader>> mLoaders;
     416             : 
     417             :   nsString mCacheName;
     418             :   OriginAttributes mOriginAttributes;
     419             : };
     420             : 
     421           0 : NS_IMPL_ISUPPORTS0(CacheCreator)
     422             : 
     423             : class CacheScriptLoader final : public PromiseNativeHandler
     424             :                               , public nsIStreamLoaderObserver
     425             : {
     426             : public:
     427             :   NS_DECL_ISUPPORTS
     428             :   NS_DECL_NSISTREAMLOADEROBSERVER
     429             : 
     430           0 :   CacheScriptLoader(WorkerPrivate* aWorkerPrivate, ScriptLoadInfo& aLoadInfo,
     431             :                     uint32_t aIndex, bool aIsWorkerScript,
     432             :                     ScriptLoaderRunnable* aRunnable)
     433           0 :     : mLoadInfo(aLoadInfo)
     434             :     , mIndex(aIndex)
     435             :     , mRunnable(aRunnable)
     436             :     , mIsWorkerScript(aIsWorkerScript)
     437           0 :     , mFailed(false)
     438             :   {
     439           0 :     MOZ_ASSERT(aWorkerPrivate);
     440           0 :     MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
     441           0 :     mMainThreadEventTarget = aWorkerPrivate->MainThreadEventTarget();
     442           0 :     MOZ_ASSERT(mMainThreadEventTarget);
     443           0 :     mBaseURI = GetBaseURI(mIsWorkerScript, aWorkerPrivate);
     444           0 :     AssertIsOnMainThread();
     445           0 :   }
     446             : 
     447             :   void
     448             :   Fail(nsresult aRv);
     449             : 
     450             :   void
     451             :   Load(Cache* aCache);
     452             : 
     453             :   virtual void
     454             :   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
     455             : 
     456             :   virtual void
     457             :   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
     458             : 
     459             : private:
     460           0 :   ~CacheScriptLoader()
     461           0 :   {
     462           0 :     AssertIsOnMainThread();
     463           0 :   }
     464             : 
     465             :   ScriptLoadInfo& mLoadInfo;
     466             :   uint32_t mIndex;
     467             :   RefPtr<ScriptLoaderRunnable> mRunnable;
     468             :   bool mIsWorkerScript;
     469             :   bool mFailed;
     470             :   nsCOMPtr<nsIInputStreamPump> mPump;
     471             :   nsCOMPtr<nsIURI> mBaseURI;
     472             :   mozilla::dom::ChannelInfo mChannelInfo;
     473             :   UniquePtr<PrincipalInfo> mPrincipalInfo;
     474             :   nsCString mCSPHeaderValue;
     475             :   nsCString mCSPReportOnlyHeaderValue;
     476             :   nsCString mReferrerPolicyHeaderValue;
     477             :   nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
     478             : };
     479             : 
     480           0 : NS_IMPL_ISUPPORTS(CacheScriptLoader, nsIStreamLoaderObserver)
     481             : 
     482             : class CachePromiseHandler final : public PromiseNativeHandler
     483             : {
     484             : public:
     485             :   NS_DECL_ISUPPORTS
     486             : 
     487           0 :   CachePromiseHandler(ScriptLoaderRunnable* aRunnable,
     488             :                       ScriptLoadInfo& aLoadInfo,
     489             :                       uint32_t aIndex)
     490           0 :     : mRunnable(aRunnable)
     491             :     , mLoadInfo(aLoadInfo)
     492           0 :     , mIndex(aIndex)
     493             :   {
     494           0 :     AssertIsOnMainThread();
     495           0 :     MOZ_ASSERT(mRunnable);
     496           0 :   }
     497             : 
     498             :   virtual void
     499             :   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
     500             : 
     501             :   virtual void
     502             :   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
     503             : 
     504             : private:
     505           0 :   ~CachePromiseHandler()
     506           0 :   {
     507           0 :     AssertIsOnMainThread();
     508           0 :   }
     509             : 
     510             :   RefPtr<ScriptLoaderRunnable> mRunnable;
     511             :   ScriptLoadInfo& mLoadInfo;
     512             :   uint32_t mIndex;
     513             : };
     514             : 
     515           0 : NS_IMPL_ISUPPORTS0(CachePromiseHandler)
     516             : 
     517             : class LoaderListener final : public nsIStreamLoaderObserver
     518             :                            , public nsIRequestObserver
     519             : {
     520             : public:
     521             :   NS_DECL_ISUPPORTS
     522             : 
     523           8 :   LoaderListener(ScriptLoaderRunnable* aRunnable, uint32_t aIndex)
     524           8 :     : mRunnable(aRunnable)
     525           8 :     , mIndex(aIndex)
     526             :   {
     527           8 :     MOZ_ASSERT(mRunnable);
     528           8 :   }
     529             : 
     530             :   NS_IMETHOD
     531             :   OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
     532             :                    nsresult aStatus, uint32_t aStringLen,
     533             :                    const uint8_t* aString) override;
     534             : 
     535             :   NS_IMETHOD
     536             :   OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) override;
     537             : 
     538             :   NS_IMETHOD
     539           0 :   OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
     540             :                 nsresult aStatusCode) override
     541             :   {
     542             :     // Nothing to do here!
     543           0 :     return NS_OK;
     544             :   }
     545             : 
     546             : private:
     547           8 :   ~LoaderListener() {}
     548             : 
     549             :   RefPtr<ScriptLoaderRunnable> mRunnable;
     550             :   uint32_t mIndex;
     551             : };
     552             : 
     553          64 : NS_IMPL_ISUPPORTS(LoaderListener, nsIStreamLoaderObserver, nsIRequestObserver)
     554             : 
     555             : class ScriptLoaderHolder;
     556             : 
     557             : class ScriptLoaderRunnable final : public nsIRunnable,
     558             :                                    public nsINamed
     559             : {
     560             :   friend class ScriptExecutorRunnable;
     561             :   friend class ScriptLoaderHolder;
     562             :   friend class CachePromiseHandler;
     563             :   friend class CacheScriptLoader;
     564             :   friend class LoaderListener;
     565             : 
     566             :   WorkerPrivate* mWorkerPrivate;
     567             :   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
     568             :   nsTArray<ScriptLoadInfo> mLoadInfos;
     569             :   RefPtr<CacheCreator> mCacheCreator;
     570             :   bool mIsMainScript;
     571             :   WorkerScriptType mWorkerScriptType;
     572             :   bool mCanceled;
     573             :   bool mCanceledMainThread;
     574             :   ErrorResult& mRv;
     575             : 
     576             : public:
     577             :   NS_DECL_THREADSAFE_ISUPPORTS
     578             : 
     579           5 :   ScriptLoaderRunnable(WorkerPrivate* aWorkerPrivate,
     580             :                        nsIEventTarget* aSyncLoopTarget,
     581             :                        nsTArray<ScriptLoadInfo>& aLoadInfos,
     582             :                        bool aIsMainScript,
     583             :                        WorkerScriptType aWorkerScriptType,
     584             :                        ErrorResult& aRv)
     585           5 :   : mWorkerPrivate(aWorkerPrivate), mSyncLoopTarget(aSyncLoopTarget),
     586             :     mIsMainScript(aIsMainScript), mWorkerScriptType(aWorkerScriptType),
     587           5 :     mCanceled(false), mCanceledMainThread(false), mRv(aRv)
     588             :   {
     589           5 :     aWorkerPrivate->AssertIsOnWorkerThread();
     590           5 :     MOZ_ASSERT(aSyncLoopTarget);
     591           5 :     MOZ_ASSERT_IF(aIsMainScript, aLoadInfos.Length() == 1);
     592             : 
     593           5 :     mLoadInfos.SwapElements(aLoadInfos);
     594           5 :   }
     595             : 
     596             : private:
     597           2 :   ~ScriptLoaderRunnable()
     598           2 :   { }
     599             : 
     600             :   NS_IMETHOD
     601           5 :   Run() override
     602             :   {
     603           5 :     AssertIsOnMainThread();
     604             : 
     605           5 :     nsresult rv = RunInternal();
     606           5 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     607           0 :       CancelMainThread(rv);
     608             :     }
     609             : 
     610           5 :     return NS_OK;
     611             :   }
     612             : 
     613             :   NS_IMETHOD
     614           5 :   GetName(nsACString& aName) override
     615             :   {
     616           5 :     aName.AssignASCII("ScriptLoaderRunnable");
     617           5 :     return NS_OK;
     618             :   }
     619             : 
     620             :   NS_IMETHOD
     621           0 :   SetName(const char* aName) override
     622             :   {
     623           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     624             :   }
     625             : 
     626             :   void
     627           8 :   LoadingFinished(uint32_t aIndex, nsresult aRv)
     628             :   {
     629           8 :     AssertIsOnMainThread();
     630           8 :     MOZ_ASSERT(aIndex < mLoadInfos.Length());
     631           8 :     ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
     632             : 
     633           8 :     loadInfo.mLoadResult = aRv;
     634             : 
     635           8 :     MOZ_ASSERT(!loadInfo.mLoadingFinished);
     636           8 :     loadInfo.mLoadingFinished = true;
     637             : 
     638           8 :     if (IsMainWorkerScript() && NS_SUCCEEDED(aRv)) {
     639           1 :       MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate->PrincipalURIMatchesScriptURL());
     640             :     }
     641             : 
     642           8 :     MaybeExecuteFinishedScripts(aIndex);
     643           8 :   }
     644             : 
     645             :   void
     646           8 :   MaybeExecuteFinishedScripts(uint32_t aIndex)
     647             :   {
     648           8 :     AssertIsOnMainThread();
     649           8 :     MOZ_ASSERT(aIndex < mLoadInfos.Length());
     650           8 :     ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
     651             : 
     652             :     // We execute the last step if we don't have a pending operation with the
     653             :     // cache and the loading is completed.
     654           8 :     if (loadInfo.Finished()) {
     655           8 :       ExecuteFinishedScripts();
     656             :     }
     657           8 :   }
     658             : 
     659             :   nsresult
     660           8 :   OnStreamComplete(nsIStreamLoader* aLoader, uint32_t aIndex,
     661             :                    nsresult aStatus, uint32_t aStringLen,
     662             :                    const uint8_t* aString)
     663             :   {
     664           8 :     AssertIsOnMainThread();
     665           8 :     MOZ_ASSERT(aIndex < mLoadInfos.Length());
     666             : 
     667             :     nsresult rv = OnStreamCompleteInternal(aLoader, aStatus, aStringLen,
     668           8 :                                            aString, mLoadInfos[aIndex]);
     669           8 :     LoadingFinished(aIndex, rv);
     670           8 :     return NS_OK;
     671             :   }
     672             : 
     673             :   nsresult
     674           0 :   OnStartRequest(nsIRequest* aRequest, uint32_t aIndex)
     675             :   {
     676           0 :     AssertIsOnMainThread();
     677           0 :     MOZ_ASSERT(aIndex < mLoadInfos.Length());
     678             : 
     679             :     // If one load info cancels or hits an error, it can race with the start
     680             :     // callback coming from another load info.
     681           0 :     if (mCanceledMainThread || !mCacheCreator) {
     682           0 :       aRequest->Cancel(NS_ERROR_FAILURE);
     683           0 :       return NS_ERROR_FAILURE;
     684             :     }
     685             : 
     686           0 :     ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
     687             : 
     688           0 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
     689           0 :     MOZ_ASSERT(channel == loadInfo.mChannel);
     690             : 
     691             :     // We synthesize the result code, but its never exposed to content.
     692             :     RefPtr<mozilla::dom::InternalResponse> ir =
     693           0 :       new mozilla::dom::InternalResponse(200, NS_LITERAL_CSTRING("OK"));
     694           0 :     ir->SetBody(loadInfo.mCacheReadStream, InternalResponse::UNKNOWN_BODY_SIZE);
     695             : 
     696             :     // Drop our reference to the stream now that we've passed it along, so it
     697             :     // doesn't hang around once the cache is done with it and keep data alive.
     698           0 :     loadInfo.mCacheReadStream = nullptr;
     699             : 
     700             :     // Set the channel info of the channel on the response so that it's
     701             :     // saved in the cache.
     702           0 :     ir->InitChannelInfo(channel);
     703             : 
     704             :     // Save the principal of the channel since its URI encodes the script URI
     705             :     // rather than the ServiceWorkerRegistrationInfo URI.
     706           0 :     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
     707           0 :     NS_ASSERTION(ssm, "Should never be null!");
     708             : 
     709           0 :     nsCOMPtr<nsIPrincipal> channelPrincipal;
     710           0 :     nsresult rv = ssm->GetChannelResultPrincipal(channel, getter_AddRefs(channelPrincipal));
     711           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     712           0 :       channel->Cancel(rv);
     713           0 :       return rv;
     714             :     }
     715             : 
     716           0 :     UniquePtr<PrincipalInfo> principalInfo(new PrincipalInfo());
     717           0 :     rv = PrincipalToPrincipalInfo(channelPrincipal, principalInfo.get());
     718           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     719           0 :       channel->Cancel(rv);
     720           0 :       return rv;
     721             :     }
     722             : 
     723           0 :     ir->SetPrincipalInfo(Move(principalInfo));
     724           0 :     ir->Headers()->FillResponseHeaders(loadInfo.mChannel);
     725             : 
     726             :     RefPtr<mozilla::dom::Response> response =
     727           0 :       new mozilla::dom::Response(mCacheCreator->Global(), ir);
     728             : 
     729           0 :     mozilla::dom::RequestOrUSVString request;
     730             : 
     731           0 :     MOZ_ASSERT(!loadInfo.mFullURL.IsEmpty());
     732           0 :     request.SetAsUSVString().Rebind(loadInfo.mFullURL.Data(),
     733           0 :                                     loadInfo.mFullURL.Length());
     734             : 
     735           0 :     ErrorResult error;
     736             :     RefPtr<Promise> cachePromise =
     737           0 :       mCacheCreator->Cache_()->Put(request, *response, error);
     738           0 :     if (NS_WARN_IF(error.Failed())) {
     739           0 :       nsresult rv = error.StealNSResult();
     740           0 :       channel->Cancel(rv);
     741           0 :       return rv;
     742             :     }
     743             : 
     744             :     RefPtr<CachePromiseHandler> promiseHandler =
     745           0 :       new CachePromiseHandler(this, loadInfo, aIndex);
     746           0 :     cachePromise->AppendNativeHandler(promiseHandler);
     747             : 
     748           0 :     loadInfo.mCachePromise.swap(cachePromise);
     749           0 :     loadInfo.mCacheStatus = ScriptLoadInfo::WritingToCache;
     750             : 
     751           0 :     return NS_OK;
     752             :   }
     753             : 
     754             :   bool
     755           0 :   Notify(Status aStatus)
     756             :   {
     757           0 :     mWorkerPrivate->AssertIsOnWorkerThread();
     758             : 
     759           0 :     if (aStatus >= Terminating && !mCanceled) {
     760           0 :       mCanceled = true;
     761             : 
     762           0 :       MOZ_ALWAYS_SUCCEEDS(
     763             :         NS_DispatchToMainThread(NewRunnableMethod("ScriptLoaderRunnable::CancelMainThreadWithBindingAborted",
     764             :                                                   this,
     765             :                                                   &ScriptLoaderRunnable::CancelMainThreadWithBindingAborted)));
     766             :     }
     767             : 
     768           0 :     return true;
     769             :   }
     770             : 
     771             :   bool
     772          67 :   IsMainWorkerScript() const
     773             :   {
     774          67 :     return mIsMainScript && mWorkerScriptType == WorkerScript;
     775             :   }
     776             : 
     777             :   void
     778           0 :   CancelMainThreadWithBindingAborted()
     779             :   {
     780           0 :     CancelMainThread(NS_BINDING_ABORTED);
     781           0 :   }
     782             : 
     783             :   void
     784           0 :   CancelMainThread(nsresult aCancelResult)
     785             :   {
     786           0 :     AssertIsOnMainThread();
     787             : 
     788           0 :     if (mCanceledMainThread) {
     789           0 :       return;
     790             :     }
     791             : 
     792           0 :     mCanceledMainThread = true;
     793             : 
     794           0 :     if (mCacheCreator) {
     795           0 :       MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
     796           0 :       DeleteCache();
     797             :     }
     798             : 
     799             :     // Cancel all the channels that were already opened.
     800           0 :     for (uint32_t index = 0; index < mLoadInfos.Length(); index++) {
     801           0 :       ScriptLoadInfo& loadInfo = mLoadInfos[index];
     802             : 
     803             :       // If promise or channel is non-null, their failures will lead to
     804             :       // LoadingFinished being called.
     805           0 :       bool callLoadingFinished = true;
     806             : 
     807           0 :       if (loadInfo.mCachePromise) {
     808           0 :         MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
     809           0 :         loadInfo.mCachePromise->MaybeReject(aCancelResult);
     810           0 :         loadInfo.mCachePromise = nullptr;
     811           0 :         callLoadingFinished = false;
     812             :       }
     813             : 
     814           0 :       if (loadInfo.mChannel) {
     815           0 :         if (NS_SUCCEEDED(loadInfo.mChannel->Cancel(aCancelResult))) {
     816           0 :           callLoadingFinished = false;
     817             :         } else {
     818           0 :           NS_WARNING("Failed to cancel channel!");
     819             :         }
     820             :       }
     821             : 
     822           0 :       if (callLoadingFinished && !loadInfo.Finished()) {
     823           0 :         LoadingFinished(index, aCancelResult);
     824             :       }
     825             :     }
     826             : 
     827           0 :     ExecuteFinishedScripts();
     828             :   }
     829             : 
     830             :   void
     831           0 :   DeleteCache()
     832             :   {
     833           0 :     AssertIsOnMainThread();
     834             : 
     835           0 :     if (!mCacheCreator) {
     836           0 :       return;
     837             :     }
     838             : 
     839           0 :     mCacheCreator->DeleteCache();
     840           0 :     mCacheCreator = nullptr;
     841             :   }
     842             : 
     843             :   nsresult
     844           5 :   RunInternal()
     845             :   {
     846           5 :     AssertIsOnMainThread();
     847             : 
     848           5 :     if (IsMainWorkerScript() && mWorkerPrivate->IsServiceWorker()) {
     849           0 :       mWorkerPrivate->SetLoadingWorkerScript(true);
     850             :     }
     851             : 
     852           5 :     if (!mWorkerPrivate->IsServiceWorker() ||
     853           0 :         !mWorkerPrivate->LoadScriptAsPartOfLoadingServiceWorkerScript()) {
     854          13 :       for (uint32_t index = 0, len = mLoadInfos.Length(); index < len;
     855             :            ++index) {
     856           8 :         nsresult rv = LoadScript(index);
     857           8 :         if (NS_WARN_IF(NS_FAILED(rv))) {
     858           0 :           LoadingFinished(index, rv);
     859           0 :           return rv;
     860             :         }
     861             :       }
     862             : 
     863           5 :       return NS_OK;
     864             :     }
     865             : 
     866           0 :     MOZ_ASSERT(!mCacheCreator);
     867           0 :     mCacheCreator = new CacheCreator(mWorkerPrivate);
     868             : 
     869           0 :     for (uint32_t index = 0, len = mLoadInfos.Length(); index < len; ++index) {
     870             :       RefPtr<CacheScriptLoader> loader =
     871           0 :         new CacheScriptLoader(mWorkerPrivate, mLoadInfos[index], index,
     872           0 :                               IsMainWorkerScript(), this);
     873           0 :       mCacheCreator->AddLoader(loader);
     874             :     }
     875             : 
     876             :     // The worker may have a null principal on first load, but in that case its
     877             :     // parent definitely will have one.
     878           0 :     nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
     879           0 :     if (!principal) {
     880           0 :       WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
     881           0 :       MOZ_ASSERT(parentWorker, "Must have a parent!");
     882           0 :       principal = parentWorker->GetPrincipal();
     883             :     }
     884             : 
     885           0 :     nsresult rv = mCacheCreator->Load(principal);
     886           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     887           0 :       return rv;
     888             :     }
     889             : 
     890           0 :     return NS_OK;
     891             :   }
     892             : 
     893             :   nsresult
     894           8 :   LoadScript(uint32_t aIndex)
     895             :   {
     896           8 :     AssertIsOnMainThread();
     897           8 :     MOZ_ASSERT(aIndex < mLoadInfos.Length());
     898             : 
     899           8 :     WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
     900             : 
     901           8 :     nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
     902          16 :     nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
     903           8 :     MOZ_DIAGNOSTIC_ASSERT(principal);
     904             : 
     905           8 :     NS_ENSURE_TRUE(NS_LoadGroupMatchesPrincipal(loadGroup, principal),
     906             :                    NS_ERROR_FAILURE);
     907             : 
     908             :     // Figure out our base URI.
     909          16 :     nsCOMPtr<nsIURI> baseURI = GetBaseURI(mIsMainScript, mWorkerPrivate);
     910             : 
     911             :     // May be null.
     912          16 :     nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
     913             : 
     914          16 :     nsCOMPtr<nsIChannel> channel;
     915           8 :     if (IsMainWorkerScript()) {
     916             :       // May be null.
     917           1 :       channel = mWorkerPrivate->ForgetWorkerChannel();
     918             :     }
     919             : 
     920          16 :     nsCOMPtr<nsIIOService> ios(do_GetIOService());
     921             : 
     922           8 :     nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
     923           8 :     NS_ASSERTION(secMan, "This should never be null!");
     924             : 
     925           8 :     ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
     926           8 :     nsresult& rv = loadInfo.mLoadResult;
     927             : 
     928           8 :     nsLoadFlags loadFlags = loadInfo.mLoadFlags;
     929             : 
     930             :     // Get the top-level worker.
     931           8 :     WorkerPrivate* topWorkerPrivate = mWorkerPrivate;
     932           8 :     WorkerPrivate* parent = topWorkerPrivate->GetParent();
     933           8 :     while (parent) {
     934           0 :       topWorkerPrivate = parent;
     935           0 :       parent = topWorkerPrivate->GetParent();
     936             :     }
     937             : 
     938             :     // If the top-level worker is a dedicated worker and has a window, and the
     939             :     // window has a docshell, the caching behavior of this worker should match
     940             :     // that of that docshell.
     941           8 :     if (topWorkerPrivate->IsDedicatedWorker()) {
     942          16 :       nsCOMPtr<nsPIDOMWindowInner> window = topWorkerPrivate->GetWindow();
     943           8 :       if (window) {
     944           0 :         nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
     945           0 :         if (docShell) {
     946           0 :           nsresult rv = docShell->GetDefaultLoadFlags(&loadFlags);
     947           0 :           NS_ENSURE_SUCCESS(rv, rv);
     948             :         }
     949             :       }
     950             :     }
     951             : 
     952           8 :     if (!channel) {
     953             :       // Only top level workers' main script use the document charset for the
     954             :       // script uri encoding. Otherwise, default encoding (UTF-8) is applied.
     955           7 :       bool useDefaultEncoding = !(!parentWorker && IsMainWorkerScript());
     956          21 :       rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios,
     957           7 :                                 secMan, loadInfo.mURL, IsMainWorkerScript(),
     958             :                                 mWorkerScriptType,
     959           7 :                                 mWorkerPrivate->ContentPolicyType(), loadFlags,
     960             :                                 useDefaultEncoding,
     961          14 :                                 getter_AddRefs(channel));
     962           7 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     963           0 :         return rv;
     964             :       }
     965             :     }
     966             : 
     967             :     // We need to know which index we're on in OnStreamComplete so we know
     968             :     // where to put the result.
     969          16 :     RefPtr<LoaderListener> listener = new LoaderListener(this, aIndex);
     970             : 
     971             :     // We don't care about progress so just use the simple stream loader for
     972             :     // OnStreamComplete notification only.
     973          16 :     nsCOMPtr<nsIStreamLoader> loader;
     974           8 :     rv = NS_NewStreamLoader(getter_AddRefs(loader), listener);
     975           8 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     976           0 :       return rv;
     977             :     }
     978             : 
     979           8 :     if (loadInfo.mCacheStatus != ScriptLoadInfo::ToBeCached) {
     980           8 :       rv = channel->AsyncOpen2(loader);
     981           8 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     982           0 :         return rv;
     983             :       }
     984             :     } else {
     985           0 :       nsCOMPtr<nsIOutputStream> writer;
     986             : 
     987             :       // In case we return early.
     988           0 :       loadInfo.mCacheStatus = ScriptLoadInfo::Cancel;
     989             : 
     990           0 :       rv = NS_NewPipe(getter_AddRefs(loadInfo.mCacheReadStream),
     991           0 :                       getter_AddRefs(writer), 0,
     992             :                       UINT32_MAX, // unlimited size to avoid writer WOULD_BLOCK case
     993             :                       true, false); // non-blocking reader, blocking writer
     994           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     995           0 :         return rv;
     996             :       }
     997             : 
     998             :       nsCOMPtr<nsIStreamListenerTee> tee =
     999           0 :         do_CreateInstance(NS_STREAMLISTENERTEE_CONTRACTID);
    1000           0 :       rv = tee->Init(loader, writer, listener);
    1001           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    1002           0 :         return rv;
    1003             :       }
    1004             : 
    1005           0 :       nsresult rv = channel->AsyncOpen2(tee);
    1006           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    1007           0 :         return rv;
    1008             :       }
    1009             :     }
    1010             : 
    1011           8 :     loadInfo.mChannel.swap(channel);
    1012             : 
    1013           8 :     return NS_OK;
    1014             :   }
    1015             : 
    1016             :   nsresult
    1017           8 :   OnStreamCompleteInternal(nsIStreamLoader* aLoader, nsresult aStatus,
    1018             :                            uint32_t aStringLen, const uint8_t* aString,
    1019             :                            ScriptLoadInfo& aLoadInfo)
    1020             :   {
    1021           8 :     AssertIsOnMainThread();
    1022             : 
    1023           8 :     if (!aLoadInfo.mChannel) {
    1024           0 :       return NS_BINDING_ABORTED;
    1025             :     }
    1026             : 
    1027           8 :     aLoadInfo.mChannel = nullptr;
    1028             : 
    1029           8 :     if (NS_FAILED(aStatus)) {
    1030           0 :       return aStatus;
    1031             :     }
    1032             : 
    1033           8 :     NS_ASSERTION(aString, "This should never be null!");
    1034             : 
    1035          16 :     nsCOMPtr<nsIRequest> request;
    1036           8 :     nsresult rv = aLoader->GetRequest(getter_AddRefs(request));
    1037           8 :     NS_ENSURE_SUCCESS(rv, rv);
    1038             : 
    1039          16 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    1040           8 :     MOZ_ASSERT(channel);
    1041             : 
    1042           8 :     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
    1043           8 :     NS_ASSERTION(ssm, "Should never be null!");
    1044             : 
    1045          16 :     nsCOMPtr<nsIPrincipal> channelPrincipal;
    1046           8 :     rv = ssm->GetChannelResultPrincipal(channel, getter_AddRefs(channelPrincipal));
    1047           8 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1048           0 :       return rv;
    1049             :     }
    1050             : 
    1051           8 :     nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
    1052           8 :     if (!principal) {
    1053           0 :       WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
    1054           0 :       MOZ_ASSERT(parentWorker, "Must have a parent!");
    1055           0 :       principal = parentWorker->GetPrincipal();
    1056             :     }
    1057             : 
    1058             :     // We don't mute the main worker script becase we've already done
    1059             :     // same-origin checks on them so we should be able to see their errors.
    1060             :     // Note that for data: url, where we allow it through the same-origin check
    1061             :     // but then give it a different origin.
    1062          16 :     aLoadInfo.mMutedErrorFlag.emplace(IsMainWorkerScript()
    1063          23 :                                         ? false
    1064          15 :                                         : !principal->Subsumes(channelPrincipal));
    1065             : 
    1066             :     // Make sure we're not seeing the result of a 404 or something by checking
    1067             :     // the 'requestSucceeded' attribute on the http channel.
    1068          16 :     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
    1069          16 :     nsAutoCString tCspHeaderValue, tCspROHeaderValue, tRPHeaderCValue;
    1070             : 
    1071           8 :     if (httpChannel) {
    1072             :       bool requestSucceeded;
    1073           0 :       rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
    1074           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1075             : 
    1076           0 :       if (!requestSucceeded) {
    1077           0 :         return NS_ERROR_NOT_AVAILABLE;
    1078             :       }
    1079             : 
    1080           0 :       Unused << httpChannel->GetResponseHeader(
    1081           0 :         NS_LITERAL_CSTRING("content-security-policy"),
    1082           0 :         tCspHeaderValue);
    1083             : 
    1084           0 :       Unused << httpChannel->GetResponseHeader(
    1085           0 :         NS_LITERAL_CSTRING("content-security-policy-report-only"),
    1086           0 :         tCspROHeaderValue);
    1087             : 
    1088           0 :       Unused << httpChannel->GetResponseHeader(
    1089           0 :         NS_LITERAL_CSTRING("referrer-policy"),
    1090           0 :         tRPHeaderCValue);
    1091             :     }
    1092             : 
    1093             :     // May be null.
    1094           8 :     nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
    1095             : 
    1096             :     // Use the regular ScriptLoader for this grunt work! Should be just fine
    1097             :     // because we're running on the main thread.
    1098             :     // Unlike <script> tags, Worker scripts are always decoded as UTF-8,
    1099             :     // per spec. So we explicitly pass in the charset hint.
    1100          16 :     rv = ScriptLoader::ConvertToUTF16(aLoadInfo.mChannel, aString, aStringLen,
    1101          16 :                                       NS_LITERAL_STRING("UTF-8"), parentDoc,
    1102             :                                       aLoadInfo.mScriptTextBuf,
    1103          16 :                                       aLoadInfo.mScriptTextLength);
    1104           8 :     if (NS_FAILED(rv)) {
    1105           0 :       return rv;
    1106             :     }
    1107             : 
    1108           8 :     if (!aLoadInfo.mScriptTextLength && !aLoadInfo.mScriptTextBuf) {
    1109           0 :       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    1110           0 :                                       NS_LITERAL_CSTRING("DOM"), parentDoc,
    1111             :                                       nsContentUtils::eDOM_PROPERTIES,
    1112           0 :                                       "EmptyWorkerSourceWarning");
    1113           8 :     } else if (!aLoadInfo.mScriptTextBuf) {
    1114           0 :       return NS_ERROR_FAILURE;
    1115             :     }
    1116             : 
    1117             :     // Figure out what we actually loaded.
    1118          16 :     nsCOMPtr<nsIURI> finalURI;
    1119           8 :     rv = NS_GetFinalChannelURI(channel, getter_AddRefs(finalURI));
    1120           8 :     NS_ENSURE_SUCCESS(rv, rv);
    1121             : 
    1122          16 :     nsCString filename;
    1123           8 :     rv = finalURI->GetSpec(filename);
    1124           8 :     NS_ENSURE_SUCCESS(rv, rv);
    1125             : 
    1126           8 :     if (!filename.IsEmpty()) {
    1127             :       // This will help callers figure out what their script url resolved to in
    1128             :       // case of errors.
    1129           8 :       aLoadInfo.mURL.Assign(NS_ConvertUTF8toUTF16(filename));
    1130             :     }
    1131             : 
    1132          16 :     nsCOMPtr<nsILoadInfo> chanLoadInfo = channel->GetLoadInfo();
    1133           8 :     if (chanLoadInfo && chanLoadInfo->GetEnforceSRI()) {
    1134             :       // importScripts() and the Worker constructor do not support integrity metadata
    1135             :       //  (or any fetch options). Until then, we can just block.
    1136             :       //  If we ever have those data in the future, we'll have to the check to
    1137             :       //  by using the SRICheck module
    1138           0 :       MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
    1139             :             ("Scriptloader::Load, SRI required but not supported in workers"));
    1140           0 :       nsCOMPtr<nsIContentSecurityPolicy> wcsp;
    1141           0 :       chanLoadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(wcsp));
    1142           0 :       MOZ_ASSERT(wcsp, "We sould have a CSP for the worker here");
    1143           0 :       if (wcsp) {
    1144           0 :         wcsp->LogViolationDetails(
    1145             :             nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
    1146           0 :             aLoadInfo.mURL, EmptyString(), 0, EmptyString(), EmptyString());
    1147             :       }
    1148           0 :       return NS_ERROR_SRI_CORRUPT;
    1149             :     }
    1150             : 
    1151             :     // Update the principal of the worker and its base URI if we just loaded the
    1152             :     // worker's primary script.
    1153           8 :     if (IsMainWorkerScript()) {
    1154             :       // Take care of the base URI first.
    1155           1 :       mWorkerPrivate->SetBaseURI(finalURI);
    1156             : 
    1157             :       // Store the channel info if needed.
    1158           1 :       mWorkerPrivate->InitChannelInfo(channel);
    1159             : 
    1160             :       // Our final channel principal should match the original principal
    1161             :       // in terms of the origin.
    1162           1 :       MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate->FinalChannelPrincipalIsValid(channel));
    1163             : 
    1164             :       // However, we must still override the principal since the nsIPrincipal
    1165             :       // URL may be different due to same-origin redirects.  Unfortunately this
    1166             :       // URL must exactly match the final worker script URL in order to
    1167             :       // properly set the referrer header on fetch/xhr requests.  If bug 1340694
    1168             :       // is ever fixed this can be removed.
    1169           1 :       rv = mWorkerPrivate->SetPrincipalFromChannel(channel);
    1170           1 :       NS_ENSURE_SUCCESS(rv, rv);
    1171             : 
    1172           2 :       nsCOMPtr<nsIContentSecurityPolicy> csp = mWorkerPrivate->GetCSP();
    1173             :       // We did inherit CSP in bug 1223647. If we do not already have a CSP, we
    1174             :       // should get it from the HTTP headers on the worker script.
    1175           1 :       if (CSPService::sCSPEnabled) {
    1176           1 :         if (!csp) {
    1177           1 :           rv = mWorkerPrivate->SetCSPFromHeaderValues(tCspHeaderValue,
    1178           1 :                                                       tCspROHeaderValue);
    1179           1 :           NS_ENSURE_SUCCESS(rv, rv);
    1180             :         } else {
    1181           0 :           csp->EnsureEventTarget(mWorkerPrivate->MainThreadEventTarget());
    1182             :         }
    1183             :       }
    1184             : 
    1185           1 :       mWorkerPrivate->SetReferrerPolicyFromHeaderValue(tRPHeaderCValue);
    1186             : 
    1187           1 :       WorkerPrivate* parent = mWorkerPrivate->GetParent();
    1188           1 :       if (parent) {
    1189             :         // XHR Params Allowed
    1190           0 :         mWorkerPrivate->SetXHRParamsAllowed(parent->XHRParamsAllowed());
    1191             :       }
    1192             :     }
    1193             : 
    1194           8 :     return NS_OK;
    1195             :   }
    1196             : 
    1197             :   void
    1198           0 :   DataReceivedFromCache(uint32_t aIndex, const uint8_t* aString,
    1199             :                         uint32_t aStringLen,
    1200             :                         const mozilla::dom::ChannelInfo& aChannelInfo,
    1201             :                         UniquePtr<PrincipalInfo> aPrincipalInfo,
    1202             :                         const nsACString& aCSPHeaderValue,
    1203             :                         const nsACString& aCSPReportOnlyHeaderValue,
    1204             :                         const nsACString& aReferrerPolicyHeaderValue)
    1205             :   {
    1206           0 :     AssertIsOnMainThread();
    1207           0 :     MOZ_ASSERT(aIndex < mLoadInfos.Length());
    1208           0 :     ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
    1209           0 :     MOZ_ASSERT(loadInfo.mCacheStatus == ScriptLoadInfo::Cached);
    1210             : 
    1211             :     nsCOMPtr<nsIPrincipal> responsePrincipal =
    1212           0 :       PrincipalInfoToPrincipal(*aPrincipalInfo);
    1213           0 :     MOZ_DIAGNOSTIC_ASSERT(responsePrincipal);
    1214             : 
    1215           0 :     nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
    1216           0 :     if (!principal) {
    1217           0 :       WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
    1218           0 :       MOZ_ASSERT(parentWorker, "Must have a parent!");
    1219           0 :       principal = parentWorker->GetPrincipal();
    1220             :     }
    1221             : 
    1222           0 :     loadInfo.mMutedErrorFlag.emplace(!principal->Subsumes(responsePrincipal));
    1223             : 
    1224             :     // May be null.
    1225           0 :     nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
    1226             : 
    1227           0 :     MOZ_ASSERT(!loadInfo.mScriptTextBuf);
    1228             : 
    1229             :     nsresult rv =
    1230           0 :       ScriptLoader::ConvertToUTF16(nullptr, aString, aStringLen,
    1231           0 :                                    NS_LITERAL_STRING("UTF-8"), parentDoc,
    1232             :                                    loadInfo.mScriptTextBuf,
    1233           0 :                                    loadInfo.mScriptTextLength);
    1234           0 :     if (NS_SUCCEEDED(rv) && IsMainWorkerScript()) {
    1235           0 :       nsCOMPtr<nsIURI> finalURI;
    1236           0 :       rv = NS_NewURI(getter_AddRefs(finalURI), loadInfo.mFullURL, nullptr, nullptr);
    1237           0 :       if (NS_SUCCEEDED(rv)) {
    1238           0 :         mWorkerPrivate->SetBaseURI(finalURI);
    1239             :       }
    1240             : 
    1241             : #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    1242           0 :       nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
    1243           0 :       MOZ_DIAGNOSTIC_ASSERT(principal);
    1244             : 
    1245           0 :       bool equal = false;
    1246           0 :       MOZ_ALWAYS_SUCCEEDS(responsePrincipal->Equals(principal, &equal));
    1247           0 :       MOZ_DIAGNOSTIC_ASSERT(equal);
    1248             : 
    1249           0 :       nsCOMPtr<nsIContentSecurityPolicy> csp;
    1250           0 :       MOZ_ALWAYS_SUCCEEDS(responsePrincipal->GetCsp(getter_AddRefs(csp)));
    1251           0 :       MOZ_DIAGNOSTIC_ASSERT(!csp);
    1252             : #endif
    1253             : 
    1254           0 :       mWorkerPrivate->InitChannelInfo(aChannelInfo);
    1255             : 
    1256           0 :       nsILoadGroup* loadGroup = mWorkerPrivate->GetLoadGroup();
    1257           0 :       MOZ_DIAGNOSTIC_ASSERT(loadGroup);
    1258             : 
    1259             :       // Override the principal on the WorkerPrivate.  This is only necessary
    1260             :       // in order to get a principal with exactly the correct URL.  The fetch
    1261             :       // referrer logic depends on the WorkerPrivate principal having a URL
    1262             :       // that matches the worker script URL.  If bug 1340694 is ever fixed
    1263             :       // this can be removed.
    1264           0 :       rv = mWorkerPrivate->SetPrincipalOnMainThread(responsePrincipal, loadGroup);
    1265           0 :       MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    1266             : 
    1267           0 :       rv = mWorkerPrivate->SetCSPFromHeaderValues(aCSPHeaderValue,
    1268           0 :                                                   aCSPReportOnlyHeaderValue);
    1269           0 :       MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    1270             : 
    1271           0 :       mWorkerPrivate->SetReferrerPolicyFromHeaderValue(aReferrerPolicyHeaderValue);
    1272             :     }
    1273             : 
    1274           0 :     if (NS_SUCCEEDED(rv)) {
    1275           0 :       DataReceived();
    1276             :     }
    1277             : 
    1278           0 :     LoadingFinished(aIndex, rv);
    1279           0 :   }
    1280             : 
    1281             :   void
    1282           0 :   DataReceived()
    1283             :   {
    1284           0 :     if (IsMainWorkerScript()) {
    1285           0 :       WorkerPrivate* parent = mWorkerPrivate->GetParent();
    1286             : 
    1287           0 :       if (parent) {
    1288             :         // XHR Params Allowed
    1289           0 :         mWorkerPrivate->SetXHRParamsAllowed(parent->XHRParamsAllowed());
    1290             : 
    1291             :         // Set Eval and ContentSecurityPolicy
    1292           0 :         mWorkerPrivate->SetCSP(parent->GetCSP());
    1293           0 :         mWorkerPrivate->SetEvalAllowed(parent->IsEvalAllowed());
    1294             :       }
    1295             :     }
    1296           0 :   }
    1297             : 
    1298             :   void
    1299           8 :   ExecuteFinishedScripts()
    1300             :   {
    1301           8 :     AssertIsOnMainThread();
    1302             : 
    1303           8 :     if (IsMainWorkerScript()) {
    1304           1 :       mWorkerPrivate->WorkerScriptLoaded();
    1305             :     }
    1306             : 
    1307           8 :     uint32_t firstIndex = UINT32_MAX;
    1308           8 :     uint32_t lastIndex = UINT32_MAX;
    1309             : 
    1310             :     // Find firstIndex based on whether mExecutionScheduled is unset.
    1311          14 :     for (uint32_t index = 0; index < mLoadInfos.Length(); index++) {
    1312          14 :       if (!mLoadInfos[index].mExecutionScheduled) {
    1313           8 :         firstIndex = index;
    1314           8 :         break;
    1315             :       }
    1316             :     }
    1317             : 
    1318             :     // Find lastIndex based on whether mChannel is set, and update
    1319             :     // mExecutionScheduled on the ones we're about to schedule.
    1320           8 :     if (firstIndex != UINT32_MAX) {
    1321          16 :       for (uint32_t index = firstIndex; index < mLoadInfos.Length(); index++) {
    1322          11 :         ScriptLoadInfo& loadInfo = mLoadInfos[index];
    1323             : 
    1324          11 :         if (!loadInfo.Finished()) {
    1325           3 :           break;
    1326             :         }
    1327             : 
    1328             :         // We can execute this one.
    1329           8 :         loadInfo.mExecutionScheduled = true;
    1330             : 
    1331           8 :         lastIndex = index;
    1332             :       }
    1333             :     }
    1334             : 
    1335             :     // This is the last index, we can unused things before the exection of the
    1336             :     // script and the stopping of the sync loop.
    1337           8 :     if (lastIndex == mLoadInfos.Length() - 1) {
    1338           5 :       mCacheCreator = nullptr;
    1339             :     }
    1340             : 
    1341           8 :     if (firstIndex != UINT32_MAX && lastIndex != UINT32_MAX) {
    1342             :       RefPtr<ScriptExecutorRunnable> runnable =
    1343           8 :         new ScriptExecutorRunnable(*this, mSyncLoopTarget, IsMainWorkerScript(),
    1344          24 :                                    firstIndex, lastIndex);
    1345           8 :       if (!runnable->Dispatch()) {
    1346           0 :         MOZ_ASSERT(false, "This should never fail!");
    1347             :       }
    1348             :     }
    1349           8 :   }
    1350             : };
    1351             : 
    1352          90 : NS_IMPL_ISUPPORTS(ScriptLoaderRunnable, nsIRunnable, nsINamed)
    1353             : 
    1354           2 : class MOZ_STACK_CLASS ScriptLoaderHolder final : public WorkerHolder
    1355             : {
    1356             :   // Raw pointer because this holder object follows the mRunnable life-time.
    1357             :   ScriptLoaderRunnable* mRunnable;
    1358             : 
    1359             : public:
    1360           5 :   explicit ScriptLoaderHolder(ScriptLoaderRunnable* aRunnable)
    1361           5 :     : mRunnable(aRunnable)
    1362             :   {
    1363           5 :     MOZ_ASSERT(aRunnable);
    1364           5 :   }
    1365             : 
    1366             :   virtual bool
    1367           0 :   Notify(Status aStatus) override
    1368             :   {
    1369           0 :     mRunnable->Notify(aStatus);
    1370           0 :     return true;
    1371             :   }
    1372             : };
    1373             : 
    1374             : NS_IMETHODIMP
    1375           8 : LoaderListener::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
    1376             :                                  nsresult aStatus, uint32_t aStringLen,
    1377             :                                  const uint8_t* aString)
    1378             : {
    1379           8 :   return mRunnable->OnStreamComplete(aLoader, mIndex, aStatus, aStringLen, aString);
    1380             : }
    1381             : 
    1382             : NS_IMETHODIMP
    1383           0 : LoaderListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
    1384             : {
    1385           0 :   return mRunnable->OnStartRequest(aRequest, mIndex);
    1386             : }
    1387             : 
    1388             : void
    1389           0 : CachePromiseHandler::ResolvedCallback(JSContext* aCx,
    1390             :                                       JS::Handle<JS::Value> aValue)
    1391             : {
    1392           0 :   AssertIsOnMainThread();
    1393             :   // May already have been canceled by CacheScriptLoader::Fail from
    1394             :   // CancelMainThread.
    1395           0 :   MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::WritingToCache ||
    1396             :              mLoadInfo.mCacheStatus == ScriptLoadInfo::Cancel);
    1397           0 :   MOZ_ASSERT_IF(mLoadInfo.mCacheStatus == ScriptLoadInfo::Cancel, !mLoadInfo.mCachePromise);
    1398             : 
    1399           0 :   if (mLoadInfo.mCachePromise) {
    1400           0 :     mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
    1401           0 :     mLoadInfo.mCachePromise = nullptr;
    1402           0 :     mRunnable->MaybeExecuteFinishedScripts(mIndex);
    1403             :   }
    1404           0 : }
    1405             : 
    1406             : void
    1407           0 : CachePromiseHandler::RejectedCallback(JSContext* aCx,
    1408             :                                       JS::Handle<JS::Value> aValue)
    1409             : {
    1410           0 :   AssertIsOnMainThread();
    1411             :   // May already have been canceled by CacheScriptLoader::Fail from
    1412             :   // CancelMainThread.
    1413           0 :   MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::WritingToCache ||
    1414             :              mLoadInfo.mCacheStatus == ScriptLoadInfo::Cancel);
    1415           0 :   mLoadInfo.mCacheStatus = ScriptLoadInfo::Cancel;
    1416             : 
    1417           0 :   mLoadInfo.mCachePromise = nullptr;
    1418             : 
    1419             :   // This will delete the cache object and will call LoadingFinished() with an
    1420             :   // error for each ongoing operation.
    1421           0 :   mRunnable->DeleteCache();
    1422           0 : }
    1423             : 
    1424             : nsresult
    1425           0 : CacheCreator::CreateCacheStorage(nsIPrincipal* aPrincipal)
    1426             : {
    1427           0 :   AssertIsOnMainThread();
    1428           0 :   MOZ_ASSERT(!mCacheStorage);
    1429           0 :   MOZ_ASSERT(aPrincipal);
    1430             : 
    1431           0 :   nsIXPConnect* xpc = nsContentUtils::XPConnect();
    1432           0 :   MOZ_ASSERT(xpc, "This should never be null!");
    1433             : 
    1434           0 :   mozilla::AutoSafeJSContext cx;
    1435           0 :   JS::Rooted<JSObject*> sandbox(cx);
    1436           0 :   nsresult rv = xpc->CreateSandbox(cx, aPrincipal, sandbox.address());
    1437           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1438           0 :     return rv;
    1439             :   }
    1440             : 
    1441           0 :   mSandboxGlobalObject = xpc::NativeGlobal(sandbox);
    1442           0 :   if (NS_WARN_IF(!mSandboxGlobalObject)) {
    1443           0 :     return NS_ERROR_FAILURE;
    1444             :   }
    1445             : 
    1446             :   // If we're in private browsing mode, don't even try to create the
    1447             :   // CacheStorage.  Instead, just fail immediately to terminate the
    1448             :   // ServiceWorker load.
    1449           0 :   if (NS_WARN_IF(mOriginAttributes.mPrivateBrowsingId > 0)) {
    1450           0 :     return NS_ERROR_DOM_SECURITY_ERR;
    1451             :   }
    1452             : 
    1453             :   // Create a CacheStorage bypassing its trusted origin checks.  The
    1454             :   // ServiceWorker has already performed its own checks before getting
    1455             :   // to this point.
    1456           0 :   ErrorResult error;
    1457             :   mCacheStorage =
    1458           0 :     CacheStorage::CreateOnMainThread(mozilla::dom::cache::CHROME_ONLY_NAMESPACE,
    1459             :                                      mSandboxGlobalObject,
    1460             :                                      aPrincipal,
    1461             :                                      false, /* privateBrowsing can't be true here */
    1462             :                                      true /* force trusted origin */,
    1463           0 :                                      error);
    1464           0 :   if (NS_WARN_IF(error.Failed())) {
    1465           0 :     return error.StealNSResult();
    1466             :   }
    1467             : 
    1468           0 :   return NS_OK;
    1469             : }
    1470             : 
    1471             : nsresult
    1472           0 : CacheCreator::Load(nsIPrincipal* aPrincipal)
    1473             : {
    1474           0 :   AssertIsOnMainThread();
    1475           0 :   MOZ_ASSERT(!mLoaders.IsEmpty());
    1476             : 
    1477           0 :   nsresult rv = CreateCacheStorage(aPrincipal);
    1478           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1479           0 :     return rv;
    1480             :   }
    1481             : 
    1482           0 :   ErrorResult error;
    1483           0 :   MOZ_ASSERT(!mCacheName.IsEmpty());
    1484           0 :   RefPtr<Promise> promise = mCacheStorage->Open(mCacheName, error);
    1485           0 :   if (NS_WARN_IF(error.Failed())) {
    1486           0 :     return error.StealNSResult();
    1487             :   }
    1488             : 
    1489           0 :   promise->AppendNativeHandler(this);
    1490           0 :   return NS_OK;
    1491             : }
    1492             : 
    1493             : void
    1494           0 : CacheCreator::FailLoaders(nsresult aRv)
    1495             : {
    1496           0 :   AssertIsOnMainThread();
    1497             : 
    1498             :   // Fail() can call LoadingFinished() which may call ExecuteFinishedScripts()
    1499             :   // which sets mCacheCreator to null, so hold a ref.
    1500           0 :   RefPtr<CacheCreator> kungfuDeathGrip = this;
    1501             : 
    1502           0 :   for (uint32_t i = 0, len = mLoaders.Length(); i < len; ++i) {
    1503           0 :     mLoaders[i]->Fail(aRv);
    1504             :   }
    1505             : 
    1506           0 :   mLoaders.Clear();
    1507           0 : }
    1508             : 
    1509             : void
    1510           0 : CacheCreator::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
    1511             : {
    1512           0 :   AssertIsOnMainThread();
    1513           0 :   FailLoaders(NS_ERROR_FAILURE);
    1514           0 : }
    1515             : 
    1516             : void
    1517           0 : CacheCreator::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
    1518             : {
    1519           0 :   AssertIsOnMainThread();
    1520             : 
    1521           0 :   if (!aValue.isObject()) {
    1522           0 :     FailLoaders(NS_ERROR_FAILURE);
    1523           0 :     return;
    1524             :   }
    1525             : 
    1526           0 :   JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
    1527           0 :   Cache* cache = nullptr;
    1528           0 :   nsresult rv = UNWRAP_OBJECT(Cache, &obj, cache);
    1529           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1530           0 :     FailLoaders(NS_ERROR_FAILURE);
    1531           0 :     return;
    1532             :   }
    1533             : 
    1534           0 :   mCache = cache;
    1535           0 :   MOZ_DIAGNOSTIC_ASSERT(mCache);
    1536             : 
    1537             :   // If the worker is canceled, CancelMainThread() will have cleared the
    1538             :   // loaders via DeleteCache().
    1539           0 :   for (uint32_t i = 0, len = mLoaders.Length(); i < len; ++i) {
    1540           0 :     MOZ_DIAGNOSTIC_ASSERT(mLoaders[i]);
    1541           0 :     mLoaders[i]->Load(cache);
    1542             :   }
    1543             : }
    1544             : 
    1545             : void
    1546           0 : CacheCreator::DeleteCache()
    1547             : {
    1548           0 :   AssertIsOnMainThread();
    1549             : 
    1550             :   // This is called when the load is canceled which can occur before
    1551             :   // mCacheStorage is initialized.
    1552           0 :   if (mCacheStorage) {
    1553             :     // It's safe to do this while Cache::Match() and Cache::Put() calls are
    1554             :     // running.
    1555           0 :     IgnoredErrorResult rv;
    1556           0 :     RefPtr<Promise> promise = mCacheStorage->Delete(mCacheName, rv);
    1557             : 
    1558             :     // We don't care to know the result of the promise object.
    1559             :   }
    1560             : 
    1561             :   // Always call this here to ensure the loaders array is cleared.
    1562           0 :   FailLoaders(NS_ERROR_FAILURE);
    1563           0 : }
    1564             : 
    1565             : void
    1566           0 : CacheScriptLoader::Fail(nsresult aRv)
    1567             : {
    1568           0 :   AssertIsOnMainThread();
    1569           0 :   MOZ_ASSERT(NS_FAILED(aRv));
    1570             : 
    1571           0 :   if (mFailed) {
    1572           0 :     return;
    1573             :   }
    1574             : 
    1575           0 :   mFailed = true;
    1576             : 
    1577           0 :   if (mPump) {
    1578           0 :     MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache);
    1579           0 :     mPump->Cancel(aRv);
    1580           0 :     mPump = nullptr;
    1581             :   }
    1582             : 
    1583           0 :   mLoadInfo.mCacheStatus = ScriptLoadInfo::Cancel;
    1584             : 
    1585             :   // Stop if the load was aborted on the main thread.
    1586             :   // Can't use Finished() because mCachePromise may still be true.
    1587           0 :   if (mLoadInfo.mLoadingFinished) {
    1588           0 :     MOZ_ASSERT(!mLoadInfo.mChannel);
    1589           0 :     MOZ_ASSERT_IF(mLoadInfo.mCachePromise,
    1590             :                   mLoadInfo.mCacheStatus == ScriptLoadInfo::WritingToCache ||
    1591             :                   mLoadInfo.mCacheStatus == ScriptLoadInfo::Cancel);
    1592           0 :     return;
    1593             :   }
    1594             : 
    1595           0 :   mRunnable->LoadingFinished(mIndex, aRv);
    1596             : }
    1597             : 
    1598             : void
    1599           0 : CacheScriptLoader::Load(Cache* aCache)
    1600             : {
    1601           0 :   AssertIsOnMainThread();
    1602           0 :   MOZ_ASSERT(aCache);
    1603             : 
    1604           0 :   nsCOMPtr<nsIURI> uri;
    1605           0 :   nsresult rv = NS_NewURI(getter_AddRefs(uri), mLoadInfo.mURL, nullptr,
    1606           0 :                           mBaseURI);
    1607           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1608           0 :     Fail(rv);
    1609           0 :     return;
    1610             :   }
    1611             : 
    1612           0 :   nsAutoCString spec;
    1613           0 :   rv = uri->GetSpec(spec);
    1614           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1615           0 :     Fail(rv);
    1616           0 :     return;
    1617             :   }
    1618             : 
    1619           0 :   MOZ_ASSERT(mLoadInfo.mFullURL.IsEmpty());
    1620           0 :   CopyUTF8toUTF16(spec, mLoadInfo.mFullURL);
    1621             : 
    1622           0 :   mozilla::dom::RequestOrUSVString request;
    1623           0 :   request.SetAsUSVString().Rebind(mLoadInfo.mFullURL.Data(),
    1624           0 :                                   mLoadInfo.mFullURL.Length());
    1625             : 
    1626           0 :   mozilla::dom::CacheQueryOptions params;
    1627             : 
    1628           0 :   ErrorResult error;
    1629           0 :   RefPtr<Promise> promise = aCache->Match(request, params, error);
    1630           0 :   if (NS_WARN_IF(error.Failed())) {
    1631           0 :     Fail(error.StealNSResult());
    1632           0 :     return;
    1633             :   }
    1634             : 
    1635           0 :   promise->AppendNativeHandler(this);
    1636             : }
    1637             : 
    1638             : void
    1639           0 : CacheScriptLoader::RejectedCallback(JSContext* aCx,
    1640             :                                     JS::Handle<JS::Value> aValue)
    1641             : {
    1642           0 :   AssertIsOnMainThread();
    1643           0 :   MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::Uncached);
    1644           0 :   Fail(NS_ERROR_FAILURE);
    1645           0 : }
    1646             : 
    1647             : void
    1648           0 : CacheScriptLoader::ResolvedCallback(JSContext* aCx,
    1649             :                                     JS::Handle<JS::Value> aValue)
    1650             : {
    1651           0 :   AssertIsOnMainThread();
    1652             :   // If we have already called 'Fail', we should not proceed.
    1653           0 :   if (mFailed) {
    1654           0 :     return;
    1655             :   }
    1656             : 
    1657           0 :   MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::Uncached);
    1658             : 
    1659             :   nsresult rv;
    1660             : 
    1661           0 :   if (aValue.isUndefined()) {
    1662           0 :     mLoadInfo.mCacheStatus = ScriptLoadInfo::ToBeCached;
    1663           0 :     rv = mRunnable->LoadScript(mIndex);
    1664           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1665           0 :       Fail(rv);
    1666             :     }
    1667           0 :     return;
    1668             :   }
    1669             : 
    1670           0 :   MOZ_ASSERT(aValue.isObject());
    1671             : 
    1672           0 :   JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
    1673           0 :   mozilla::dom::Response* response = nullptr;
    1674           0 :   rv = UNWRAP_OBJECT(Response, &obj, response);
    1675           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1676           0 :     Fail(rv);
    1677           0 :     return;
    1678             :   }
    1679             : 
    1680           0 :   InternalHeaders* headers = response->GetInternalHeaders();
    1681             : 
    1682           0 :   IgnoredErrorResult ignored;
    1683           0 :   headers->Get(NS_LITERAL_CSTRING("content-security-policy"),
    1684           0 :                mCSPHeaderValue, ignored);
    1685           0 :   headers->Get(NS_LITERAL_CSTRING("content-security-policy-report-only"),
    1686           0 :                mCSPReportOnlyHeaderValue, ignored);
    1687           0 :   headers->Get(NS_LITERAL_CSTRING("referrer-policy"),
    1688           0 :                mReferrerPolicyHeaderValue, ignored);
    1689             : 
    1690           0 :   nsCOMPtr<nsIInputStream> inputStream;
    1691           0 :   response->GetBody(getter_AddRefs(inputStream));
    1692           0 :   mChannelInfo = response->GetChannelInfo();
    1693           0 :   const UniquePtr<PrincipalInfo>& pInfo = response->GetPrincipalInfo();
    1694           0 :   if (pInfo) {
    1695           0 :     mPrincipalInfo = mozilla::MakeUnique<PrincipalInfo>(*pInfo);
    1696             :   }
    1697             : 
    1698           0 :   if (!inputStream) {
    1699           0 :     mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
    1700           0 :     mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0, mChannelInfo,
    1701           0 :                                      Move(mPrincipalInfo), mCSPHeaderValue,
    1702             :                                      mCSPReportOnlyHeaderValue,
    1703           0 :                                      mReferrerPolicyHeaderValue);
    1704           0 :     return;
    1705             :   }
    1706             : 
    1707           0 :   MOZ_ASSERT(!mPump);
    1708           0 :   rv = NS_NewInputStreamPump(getter_AddRefs(mPump),
    1709             :                              inputStream,
    1710             :                              -1, /* default streamPos */
    1711             :                              -1, /* default streamLen */
    1712             :                              0, /* default segsize */
    1713             :                              0, /* default segcount */
    1714             :                              false, /* default closeWhenDone */
    1715           0 :                              mMainThreadEventTarget);
    1716           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1717           0 :     Fail(rv);
    1718           0 :     return;
    1719             :   }
    1720             : 
    1721           0 :   nsCOMPtr<nsIStreamLoader> loader;
    1722           0 :   rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
    1723           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1724           0 :     Fail(rv);
    1725           0 :     return;
    1726             :   }
    1727             : 
    1728           0 :   rv = mPump->AsyncRead(loader, nullptr);
    1729           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1730           0 :     mPump = nullptr;
    1731           0 :     Fail(rv);
    1732           0 :     return;
    1733             :   }
    1734             : 
    1735             : 
    1736           0 :   nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(mPump);
    1737           0 :   if (rr) {
    1738             :     nsCOMPtr<nsIEventTarget> sts =
    1739           0 :       do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
    1740           0 :     rv = rr->RetargetDeliveryTo(sts);
    1741           0 :     if (NS_FAILED(rv)) {
    1742           0 :       NS_WARNING("Failed to dispatch the nsIInputStreamPump to a IO thread.");
    1743             :     }
    1744             :   }
    1745             : 
    1746           0 :   mLoadInfo.mCacheStatus = ScriptLoadInfo::ReadingFromCache;
    1747             : }
    1748             : 
    1749             : NS_IMETHODIMP
    1750           0 : CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
    1751             :                                     nsresult aStatus, uint32_t aStringLen,
    1752             :                                     const uint8_t* aString)
    1753             : {
    1754           0 :   AssertIsOnMainThread();
    1755             : 
    1756           0 :   mPump = nullptr;
    1757             : 
    1758           0 :   if (NS_FAILED(aStatus)) {
    1759           0 :     MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache ||
    1760             :                mLoadInfo.mCacheStatus == ScriptLoadInfo::Cancel);
    1761           0 :     Fail(aStatus);
    1762           0 :     return NS_OK;
    1763             :   }
    1764             : 
    1765           0 :   MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache);
    1766           0 :   mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
    1767             : 
    1768           0 :   MOZ_ASSERT(mPrincipalInfo);
    1769           0 :   mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mChannelInfo,
    1770           0 :                                    Move(mPrincipalInfo), mCSPHeaderValue,
    1771             :                                    mCSPReportOnlyHeaderValue,
    1772           0 :                                    mReferrerPolicyHeaderValue);
    1773           0 :   return NS_OK;
    1774             : }
    1775             : 
    1776             : class ChannelGetterRunnable final : public WorkerMainThreadRunnable
    1777             : {
    1778             :   const nsAString& mScriptURL;
    1779             :   WorkerLoadInfo& mLoadInfo;
    1780             :   nsresult mResult;
    1781             : 
    1782             : public:
    1783           0 :   ChannelGetterRunnable(WorkerPrivate* aParentWorker,
    1784             :                         const nsAString& aScriptURL,
    1785             :                         WorkerLoadInfo& aLoadInfo)
    1786           0 :     : WorkerMainThreadRunnable(aParentWorker,
    1787           0 :                                NS_LITERAL_CSTRING("ScriptLoader :: ChannelGetter"))
    1788             :     , mScriptURL(aScriptURL)
    1789             :     , mLoadInfo(aLoadInfo)
    1790           0 :     , mResult(NS_ERROR_FAILURE)
    1791             :   {
    1792           0 :     MOZ_ASSERT(aParentWorker);
    1793           0 :     aParentWorker->AssertIsOnWorkerThread();
    1794           0 :   }
    1795             : 
    1796             :   virtual bool
    1797           0 :   MainThreadRun() override
    1798             :   {
    1799           0 :     AssertIsOnMainThread();
    1800             : 
    1801             :     // Initialize the WorkerLoadInfo principal to our triggering principal
    1802             :     // before doing anything else.  Normally we do this in the WorkerPrivate
    1803             :     // Constructor, but we can't do so off the main thread when creating
    1804             :     // a nested worker.  So do it here instead.
    1805           0 :     mLoadInfo.mPrincipal = mWorkerPrivate->GetPrincipal();
    1806           0 :     MOZ_ASSERT(mLoadInfo.mPrincipal);
    1807             : 
    1808             :     // Figure out our base URI.
    1809           0 :     nsCOMPtr<nsIURI> baseURI = mWorkerPrivate->GetBaseURI();
    1810           0 :     MOZ_ASSERT(baseURI);
    1811             : 
    1812             :     // May be null.
    1813           0 :     nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
    1814             : 
    1815           0 :     mLoadInfo.mLoadGroup = mWorkerPrivate->GetLoadGroup();
    1816             : 
    1817           0 :     nsCOMPtr<nsIChannel> channel;
    1818           0 :     mResult =
    1819           0 :       scriptloader::ChannelFromScriptURLMainThread(mLoadInfo.mPrincipal,
    1820             :                                                    baseURI, parentDoc,
    1821           0 :                                                    mLoadInfo.mLoadGroup,
    1822             :                                                    mScriptURL,
    1823             :                                                    // Nested workers are always dedicated.
    1824             :                                                    nsIContentPolicy::TYPE_INTERNAL_WORKER,
    1825             :                                                    // Nested workers use default uri encoding.
    1826             :                                                    true,
    1827           0 :                                                    getter_AddRefs(channel));
    1828           0 :     NS_ENSURE_SUCCESS(mResult, true);
    1829             : 
    1830           0 :     mResult = mLoadInfo.SetPrincipalFromChannel(channel);
    1831           0 :     NS_ENSURE_SUCCESS(mResult, true);
    1832             : 
    1833           0 :     mLoadInfo.mChannel = channel.forget();
    1834           0 :     return true;
    1835             :   }
    1836             : 
    1837             :   nsresult
    1838           0 :   GetResult() const
    1839             :   {
    1840           0 :     return mResult;
    1841             :   }
    1842             : 
    1843             : private:
    1844           0 :   virtual ~ChannelGetterRunnable()
    1845           0 :   { }
    1846             : };
    1847             : 
    1848           8 : ScriptExecutorRunnable::ScriptExecutorRunnable(
    1849             :                                             ScriptLoaderRunnable& aScriptLoader,
    1850             :                                             nsIEventTarget* aSyncLoopTarget,
    1851             :                                             bool aIsWorkerScript,
    1852             :                                             uint32_t aFirstIndex,
    1853           8 :                                             uint32_t aLastIndex)
    1854             : : MainThreadWorkerSyncRunnable(aScriptLoader.mWorkerPrivate, aSyncLoopTarget),
    1855             :   mScriptLoader(aScriptLoader), mIsWorkerScript(aIsWorkerScript),
    1856           8 :   mFirstIndex(aFirstIndex), mLastIndex(aLastIndex)
    1857             : {
    1858           8 :   MOZ_ASSERT(aFirstIndex <= aLastIndex);
    1859           8 :   MOZ_ASSERT(aLastIndex < aScriptLoader.mLoadInfos.Length());
    1860           8 : }
    1861             : 
    1862             : bool
    1863           1 : ScriptExecutorRunnable::IsDebuggerRunnable() const
    1864             : {
    1865             :   // ScriptExecutorRunnable is used to execute both worker and debugger scripts.
    1866             :   // In the latter case, the runnable needs to be dispatched to the debugger
    1867             :   // queue.
    1868           1 :   return mScriptLoader.mWorkerScriptType == DebuggerScript;
    1869             : }
    1870             : 
    1871             : bool
    1872           6 : ScriptExecutorRunnable::PreRun(WorkerPrivate* aWorkerPrivate)
    1873             : {
    1874           6 :   aWorkerPrivate->AssertIsOnWorkerThread();
    1875             : 
    1876           6 :   if (!mIsWorkerScript) {
    1877           5 :     return true;
    1878             :   }
    1879             : 
    1880           1 :   if (!aWorkerPrivate->GetJSContext()) {
    1881           0 :     return false;
    1882             :   }
    1883             : 
    1884           1 :   MOZ_ASSERT(mFirstIndex == 0);
    1885           1 :   MOZ_ASSERT(!mScriptLoader.mRv.Failed());
    1886             : 
    1887           2 :   AutoJSAPI jsapi;
    1888           1 :   jsapi.Init();
    1889             : 
    1890             :   WorkerGlobalScope* globalScope =
    1891           1 :     aWorkerPrivate->GetOrCreateGlobalScope(jsapi.cx());
    1892           1 :   if (NS_WARN_IF(!globalScope)) {
    1893           0 :     NS_WARNING("Failed to make global!");
    1894             :     // There's no way to report the exception on jsapi right now, because there
    1895             :     // is no way to even enter a compartment on this thread anymore.  Just clear
    1896             :     // the exception.  We'll report some sort of error to our caller in
    1897             :     // ShutdownScriptLoader, but it will get squelched for the same reason we're
    1898             :     // squelching here: all the error reporting machinery relies on being able
    1899             :     // to enter a compartment to report the error.
    1900           0 :     jsapi.ClearException();
    1901           0 :     return false;
    1902             :   }
    1903             : 
    1904           1 :   return true;
    1905             : }
    1906             : 
    1907             : bool
    1908           6 : ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
    1909             : {
    1910           6 :   aWorkerPrivate->AssertIsOnWorkerThread();
    1911             : 
    1912           6 :   nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos;
    1913             : 
    1914             :   // Don't run if something else has already failed.
    1915           7 :   for (uint32_t index = 0; index < mFirstIndex; index++) {
    1916           1 :     ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
    1917             : 
    1918           1 :     NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
    1919           1 :     NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
    1920             : 
    1921           1 :     if (!loadInfo.mExecutionResult) {
    1922           0 :       return true;
    1923             :     }
    1924             :   }
    1925             : 
    1926             :   // If nothing else has failed, our ErrorResult better not be a failure either.
    1927           6 :   MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
    1928             : 
    1929             :   // Slightly icky action at a distance, but there's no better place to stash
    1930             :   // this value, really.
    1931           9 :   JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
    1932           6 :   MOZ_ASSERT(global);
    1933             : 
    1934           9 :   for (uint32_t index = mFirstIndex; index <= mLastIndex; index++) {
    1935           6 :     ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
    1936             : 
    1937           6 :     NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
    1938           6 :     NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
    1939           6 :     NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!");
    1940             : 
    1941           6 :     MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
    1942           6 :     mScriptLoader.mRv.MightThrowJSException();
    1943           6 :     if (NS_FAILED(loadInfo.mLoadResult)) {
    1944           0 :       scriptloader::ReportLoadError(mScriptLoader.mRv,
    1945           0 :                                     loadInfo.mLoadResult, loadInfo.mURL);
    1946             :       // Top level scripts only!
    1947           0 :       if (mIsWorkerScript) {
    1948           0 :         aWorkerPrivate->MaybeDispatchLoadFailedRunnable();
    1949             :       }
    1950           0 :       return true;
    1951             :     }
    1952             : 
    1953           9 :     NS_ConvertUTF16toUTF8 filename(loadInfo.mURL);
    1954             : 
    1955           9 :     JS::CompileOptions options(aCx);
    1956           6 :     options.setFileAndLine(filename.get(), 1)
    1957           6 :            .setNoScriptRval(true);
    1958             : 
    1959           6 :     if (mScriptLoader.mWorkerScriptType == DebuggerScript) {
    1960           0 :       options.setVersion(JSVERSION_LATEST);
    1961             :     }
    1962             : 
    1963           6 :     MOZ_ASSERT(loadInfo.mMutedErrorFlag.isSome());
    1964           6 :     options.setMutedErrors(loadInfo.mMutedErrorFlag.valueOr(true));
    1965             : 
    1966           6 :     JS::SourceBufferHolder srcBuf(loadInfo.mScriptTextBuf,
    1967             :                                   loadInfo.mScriptTextLength,
    1968          15 :                                   JS::SourceBufferHolder::GiveOwnership);
    1969           6 :     loadInfo.mScriptTextBuf = nullptr;
    1970           6 :     loadInfo.mScriptTextLength = 0;
    1971             : 
    1972             :     // Our ErrorResult still shouldn't be a failure.
    1973           6 :     MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
    1974           9 :     JS::Rooted<JS::Value> unused(aCx);
    1975           6 :     if (!JS::Evaluate(aCx, options, srcBuf, &unused)) {
    1976           0 :       mScriptLoader.mRv.StealExceptionFromJSContext(aCx);
    1977           0 :       return true;
    1978             :     }
    1979             : 
    1980           3 :     loadInfo.mExecutionResult = true;
    1981             :   }
    1982             : 
    1983           3 :   return true;
    1984             : }
    1985             : 
    1986             : void
    1987           3 : ScriptExecutorRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
    1988             :                                 bool aRunResult)
    1989             : {
    1990           3 :   aWorkerPrivate->AssertIsOnWorkerThread();
    1991           3 :   MOZ_ASSERT(!JS_IsExceptionPending(aCx), "Who left an exception on there?");
    1992             : 
    1993           3 :   nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos;
    1994             : 
    1995           3 :   if (mLastIndex == loadInfos.Length() - 1) {
    1996             :     // All done. If anything failed then return false.
    1997           2 :     bool result = true;
    1998           2 :     bool mutedError = false;
    1999           4 :     for (uint32_t index = 0; index < loadInfos.Length(); index++) {
    2000           2 :       if (!loadInfos[index].mExecutionResult) {
    2001           0 :         mutedError = loadInfos[index].mMutedErrorFlag.valueOr(true);
    2002           0 :         result = false;
    2003           0 :         break;
    2004             :       }
    2005             :     }
    2006             : 
    2007             :     // The only way we can get here with "result" false but without
    2008             :     // mScriptLoader.mRv being a failure is if we're loading the main worker
    2009             :     // script and GetOrCreateGlobalScope() fails.  In that case we would have
    2010             :     // returned false from WorkerRun, so assert that.
    2011           2 :     MOZ_ASSERT_IF(!result && !mScriptLoader.mRv.Failed(),
    2012             :                   !aRunResult);
    2013           2 :     ShutdownScriptLoader(aCx, aWorkerPrivate, result, mutedError);
    2014             :   }
    2015           3 : }
    2016             : 
    2017             : nsresult
    2018           0 : ScriptExecutorRunnable::Cancel()
    2019             : {
    2020           0 :   if (mLastIndex == mScriptLoader.mLoadInfos.Length() - 1) {
    2021           0 :     ShutdownScriptLoader(mWorkerPrivate->GetJSContext(), mWorkerPrivate,
    2022           0 :                          false, false);
    2023             :   }
    2024           0 :   return MainThreadWorkerSyncRunnable::Cancel();
    2025             : }
    2026             : 
    2027             : void
    2028           2 : ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx,
    2029             :                                              WorkerPrivate* aWorkerPrivate,
    2030             :                                              bool aResult,
    2031             :                                              bool aMutedError)
    2032             : {
    2033           2 :   aWorkerPrivate->AssertIsOnWorkerThread();
    2034             : 
    2035           2 :   MOZ_ASSERT(mLastIndex == mScriptLoader.mLoadInfos.Length() - 1);
    2036             : 
    2037           2 :   if (mIsWorkerScript && aWorkerPrivate->IsServiceWorker()) {
    2038           0 :     aWorkerPrivate->SetLoadingWorkerScript(false);
    2039             :   }
    2040             : 
    2041           2 :   if (!aResult) {
    2042             :     // At this point there are two possibilities:
    2043             :     //
    2044             :     // 1) mScriptLoader.mRv.Failed().  In that case we just want to leave it
    2045             :     //    as-is, except if it has a JS exception and we need to mute JS
    2046             :     //    exceptions.  In that case, we log the exception without firing any
    2047             :     //    events and then replace it on the ErrorResult with a NetworkError,
    2048             :     //    per spec.
    2049             :     //
    2050             :     // 2) mScriptLoader.mRv succeeded.  As far as I can tell, this can only
    2051             :     //    happen when loading the main worker script and
    2052             :     //    GetOrCreateGlobalScope() fails or if ScriptExecutorRunnable::Cancel
    2053             :     //    got called.  Does it matter what we throw in this case?  I'm not
    2054             :     //    sure...
    2055           0 :     if (mScriptLoader.mRv.Failed()) {
    2056           0 :       if (aMutedError && mScriptLoader.mRv.IsJSException()) {
    2057           0 :         LogExceptionToConsole(aCx, aWorkerPrivate);
    2058           0 :         mScriptLoader.mRv.ThrowWithCustomCleanup(NS_ERROR_DOM_NETWORK_ERR);
    2059             :       }
    2060             :     } else {
    2061           0 :       mScriptLoader.mRv.ThrowWithCustomCleanup(NS_ERROR_DOM_INVALID_STATE_ERR);
    2062             :     }
    2063             :   }
    2064             : 
    2065           2 :   aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, aResult);
    2066           2 : }
    2067             : 
    2068             : void
    2069           0 : ScriptExecutorRunnable::LogExceptionToConsole(JSContext* aCx,
    2070             :                                               WorkerPrivate* aWorkerPrivate)
    2071             : {
    2072           0 :   aWorkerPrivate->AssertIsOnWorkerThread();
    2073             : 
    2074           0 :   MOZ_ASSERT(mScriptLoader.mRv.IsJSException());
    2075             : 
    2076           0 :   JS::Rooted<JS::Value> exn(aCx);
    2077           0 :   if (!ToJSValue(aCx, mScriptLoader.mRv, &exn)) {
    2078           0 :     return;
    2079             :   }
    2080             : 
    2081             :   // Now the exception state should all be in exn.
    2082           0 :   MOZ_ASSERT(!JS_IsExceptionPending(aCx));
    2083           0 :   MOZ_ASSERT(!mScriptLoader.mRv.Failed());
    2084             : 
    2085           0 :   js::ErrorReport report(aCx);
    2086           0 :   if (!report.init(aCx, exn, js::ErrorReport::WithSideEffects)) {
    2087           0 :     JS_ClearPendingException(aCx);
    2088           0 :     return;
    2089             :   }
    2090             : 
    2091           0 :   RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
    2092           0 :   xpcReport->Init(report.report(), report.toStringResult().c_str(),
    2093           0 :                   aWorkerPrivate->IsChromeWorker(), aWorkerPrivate->WindowID());
    2094             : 
    2095           0 :   RefPtr<AsyncErrorReporter> r = new AsyncErrorReporter(xpcReport);
    2096           0 :   NS_DispatchToMainThread(r);
    2097             : }
    2098             : 
    2099             : void
    2100           5 : LoadAllScripts(WorkerPrivate* aWorkerPrivate,
    2101             :                nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsMainScript,
    2102             :                WorkerScriptType aWorkerScriptType, ErrorResult& aRv)
    2103             : {
    2104           5 :   aWorkerPrivate->AssertIsOnWorkerThread();
    2105           5 :   NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!");
    2106             : 
    2107           7 :   AutoSyncLoopHolder syncLoop(aWorkerPrivate, Terminating);
    2108           7 :   nsCOMPtr<nsIEventTarget> syncLoopTarget = syncLoop.GetEventTarget();
    2109           5 :   if (!syncLoopTarget) {
    2110           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2111           0 :     return;
    2112             :   }
    2113             : 
    2114             :   RefPtr<ScriptLoaderRunnable> loader =
    2115             :     new ScriptLoaderRunnable(aWorkerPrivate, syncLoopTarget, aLoadInfos,
    2116          12 :                              aIsMainScript, aWorkerScriptType, aRv);
    2117             : 
    2118           5 :   NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
    2119             : 
    2120           7 :   ScriptLoaderHolder workerHolder(loader);
    2121             : 
    2122           5 :   if (NS_WARN_IF(!workerHolder.HoldWorker(aWorkerPrivate, Terminating))) {
    2123           0 :     aRv.Throw(NS_ERROR_FAILURE);
    2124           0 :     return;
    2125             :   }
    2126             : 
    2127           5 :   if (NS_FAILED(NS_DispatchToMainThread(loader))) {
    2128           0 :     NS_ERROR("Failed to dispatch!");
    2129           0 :     aRv.Throw(NS_ERROR_FAILURE);
    2130           0 :     return;
    2131             :   }
    2132             : 
    2133           5 :   syncLoop.Run();
    2134             : }
    2135             : 
    2136             : } /* anonymous namespace */
    2137             : 
    2138             : BEGIN_WORKERS_NAMESPACE
    2139             : 
    2140             : namespace scriptloader {
    2141             : 
    2142             : nsresult
    2143           1 : ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
    2144             :                                nsIURI* aBaseURI,
    2145             :                                nsIDocument* aParentDoc,
    2146             :                                nsILoadGroup* aLoadGroup,
    2147             :                                const nsAString& aScriptURL,
    2148             :                                nsContentPolicyType aMainScriptContentPolicyType,
    2149             :                                bool aDefaultURIEncoding,
    2150             :                                nsIChannel** aChannel)
    2151             : {
    2152           1 :   AssertIsOnMainThread();
    2153             : 
    2154           2 :   nsCOMPtr<nsIIOService> ios(do_GetIOService());
    2155             : 
    2156           1 :   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
    2157           1 :   NS_ASSERTION(secMan, "This should never be null!");
    2158             : 
    2159           1 :   return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup,
    2160             :                               ios, secMan, aScriptURL, true, WorkerScript,
    2161             :                               aMainScriptContentPolicyType,
    2162             :                               nsIRequest::LOAD_NORMAL, aDefaultURIEncoding,
    2163           2 :                               aChannel);
    2164             : }
    2165             : 
    2166             : nsresult
    2167           0 : ChannelFromScriptURLWorkerThread(JSContext* aCx,
    2168             :                                  WorkerPrivate* aParent,
    2169             :                                  const nsAString& aScriptURL,
    2170             :                                  WorkerLoadInfo& aLoadInfo)
    2171             : {
    2172           0 :   aParent->AssertIsOnWorkerThread();
    2173             : 
    2174             :   RefPtr<ChannelGetterRunnable> getter =
    2175           0 :     new ChannelGetterRunnable(aParent, aScriptURL, aLoadInfo);
    2176             : 
    2177           0 :   ErrorResult rv;
    2178           0 :   getter->Dispatch(Terminating, rv);
    2179           0 :   if (rv.Failed()) {
    2180           0 :     NS_ERROR("Failed to dispatch!");
    2181           0 :     return rv.StealNSResult();
    2182             :   }
    2183             : 
    2184           0 :   return getter->GetResult();
    2185             : }
    2186             : 
    2187           0 : void ReportLoadError(ErrorResult& aRv, nsresult aLoadResult,
    2188             :                      const nsAString& aScriptURL)
    2189             : {
    2190           0 :   MOZ_ASSERT(!aRv.Failed());
    2191             : 
    2192           0 :   switch (aLoadResult) {
    2193             :     case NS_ERROR_FILE_NOT_FOUND:
    2194             :     case NS_ERROR_NOT_AVAILABLE:
    2195           0 :       aLoadResult = NS_ERROR_DOM_NETWORK_ERR;
    2196           0 :       break;
    2197             : 
    2198             :     case NS_ERROR_MALFORMED_URI:
    2199           0 :       aLoadResult = NS_ERROR_DOM_SYNTAX_ERR;
    2200           0 :       break;
    2201             : 
    2202             :     case NS_BINDING_ABORTED:
    2203             :       // Note: we used to pretend like we didn't set an exception for
    2204             :       // NS_BINDING_ABORTED, but then ShutdownScriptLoader did it anyway.  The
    2205             :       // other callsite, in WorkerPrivate::Constructor, never passed in
    2206             :       // NS_BINDING_ABORTED.  So just throw it directly here.  Consumers will
    2207             :       // deal as needed.  But note that we do NOT want to ThrowDOMException()
    2208             :       // for this case, because that will make it impossible for consumers to
    2209             :       // realize that our error was NS_BINDING_ABORTED.
    2210           0 :       aRv.Throw(aLoadResult);
    2211           0 :       return;
    2212             : 
    2213             :     case NS_ERROR_DOM_SECURITY_ERR:
    2214             :     case NS_ERROR_DOM_SYNTAX_ERR:
    2215           0 :       break;
    2216             : 
    2217             :     case NS_ERROR_DOM_BAD_URI:
    2218             :       // This is actually a security error.
    2219           0 :       aLoadResult = NS_ERROR_DOM_SECURITY_ERR;
    2220           0 :       break;
    2221             : 
    2222             :     default:
    2223             :       // For lack of anything better, go ahead and throw a NetworkError here.
    2224             :       // We don't want to throw a JS exception, because for toplevel script
    2225             :       // loads that would get squelched.
    2226           0 :       aRv.ThrowDOMException(NS_ERROR_DOM_NETWORK_ERR,
    2227           0 :         nsPrintfCString("Failed to load worker script at %s (nsresult = 0x%" PRIx32 ")",
    2228           0 :                         NS_ConvertUTF16toUTF8(aScriptURL).get(),
    2229           0 :                         static_cast<uint32_t>(aLoadResult)));
    2230           0 :       return;
    2231             :   }
    2232             : 
    2233           0 :   aRv.ThrowDOMException(aLoadResult,
    2234           0 :                         NS_LITERAL_CSTRING("Failed to load worker script at \"") +
    2235           0 :                         NS_ConvertUTF16toUTF8(aScriptURL) +
    2236           0 :                         NS_LITERAL_CSTRING("\""));
    2237             : }
    2238             : 
    2239             : void
    2240           1 : LoadMainScript(WorkerPrivate* aWorkerPrivate,
    2241             :                const nsAString& aScriptURL,
    2242             :                WorkerScriptType aWorkerScriptType,
    2243             :                ErrorResult& aRv)
    2244             : {
    2245           1 :   nsTArray<ScriptLoadInfo> loadInfos;
    2246             : 
    2247           1 :   ScriptLoadInfo* info = loadInfos.AppendElement();
    2248           1 :   info->mURL = aScriptURL;
    2249           1 :   info->mLoadFlags = aWorkerPrivate->GetLoadFlags();
    2250             : 
    2251           1 :   LoadAllScripts(aWorkerPrivate, loadInfos, true, aWorkerScriptType, aRv);
    2252           0 : }
    2253             : 
    2254             : void
    2255           4 : Load(WorkerPrivate* aWorkerPrivate,
    2256             :      const nsTArray<nsString>& aScriptURLs, WorkerScriptType aWorkerScriptType,
    2257             :      ErrorResult& aRv)
    2258             : {
    2259           4 :   const uint32_t urlCount = aScriptURLs.Length();
    2260             : 
    2261           4 :   if (!urlCount) {
    2262           0 :     return;
    2263             :   }
    2264             : 
    2265           4 :   if (urlCount > MAX_CONCURRENT_SCRIPTS) {
    2266           0 :     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    2267           0 :     return;
    2268             :   }
    2269             : 
    2270           6 :   nsTArray<ScriptLoadInfo> loadInfos;
    2271           4 :   loadInfos.SetLength(urlCount);
    2272             : 
    2273          11 :   for (uint32_t index = 0; index < urlCount; index++) {
    2274           7 :     loadInfos[index].mURL = aScriptURLs[index];
    2275           7 :     loadInfos[index].mLoadFlags = aWorkerPrivate->GetLoadFlags();
    2276             :   }
    2277             : 
    2278           4 :   LoadAllScripts(aWorkerPrivate, loadInfos, false, aWorkerScriptType, aRv);
    2279             : }
    2280             : 
    2281             : } // namespace scriptloader
    2282             : 
    2283             : END_WORKERS_NAMESPACE

Generated by: LCOV version 1.13