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 /*
8  * A class that handles loading and evaluation of <script> elements.
9  */
10 
11 #ifndef __nsScriptLoader_h__
12 #define __nsScriptLoader_h__
13 
14 #include "nsCOMPtr.h"
15 #include "nsRefPtrHashtable.h"
16 #include "nsIUnicodeDecoder.h"
17 #include "nsIScriptElement.h"
18 #include "nsCOMArray.h"
19 #include "nsCycleCollectionParticipant.h"
20 #include "nsTArray.h"
21 #include "nsAutoPtr.h"
22 #include "nsIDocument.h"
23 #include "nsIIncrementalStreamLoader.h"
24 #include "nsURIHashKey.h"
25 #include "mozilla/CORSMode.h"
26 #include "mozilla/dom/SRIMetadata.h"
27 #include "mozilla/dom/SRICheck.h"
28 #include "mozilla/LinkedList.h"
29 #include "mozilla/MozPromise.h"
30 #include "mozilla/net/ReferrerPolicy.h"
31 #include "mozilla/Vector.h"
32 
33 class nsModuleLoadRequest;
34 class nsModuleScript;
35 class nsScriptLoadRequestList;
36 class nsIURI;
37 
38 namespace JS {
39   class SourceBufferHolder;
40 } // namespace JS
41 
42 namespace mozilla {
43 namespace dom {
44 class AutoJSAPI;
45 } // namespace dom
46 } // namespace mozilla
47 
48 //////////////////////////////////////////////////////////////
49 // Per-request data structure
50 //////////////////////////////////////////////////////////////
51 
52 enum class nsScriptKind {
53   Classic,
54   Module
55 };
56 
57 class nsScriptLoadRequest : public nsISupports,
58                             private mozilla::LinkedListElement<nsScriptLoadRequest>
59 {
60   typedef LinkedListElement<nsScriptLoadRequest> super;
61 
62   // Allow LinkedListElement<nsScriptLoadRequest> to cast us to itself as needed.
63   friend class mozilla::LinkedListElement<nsScriptLoadRequest>;
64   friend class nsScriptLoadRequestList;
65 
66 protected:
67   virtual ~nsScriptLoadRequest();
68 
69 public:
nsScriptLoadRequest(nsScriptKind aKind,nsIScriptElement * aElement,uint32_t aVersion,mozilla::CORSMode aCORSMode,const mozilla::dom::SRIMetadata & aIntegrity)70   nsScriptLoadRequest(nsScriptKind aKind,
71                       nsIScriptElement* aElement,
72                       uint32_t aVersion,
73                       mozilla::CORSMode aCORSMode,
74                       const mozilla::dom::SRIMetadata &aIntegrity)
75     : mKind(aKind),
76       mElement(aElement),
77       mProgress(Progress::Loading),
78       mIsInline(true),
79       mHasSourceMapURL(false),
80       mIsDefer(false),
81       mIsAsync(false),
82       mIsNonAsyncScriptInserted(false),
83       mIsXSLT(false),
84       mIsCanceled(false),
85       mWasCompiledOMT(false),
86       mOffThreadToken(nullptr),
87       mScriptTextBuf(nullptr),
88       mScriptTextLength(0),
89       mJSVersion(aVersion),
90       mLineNo(1),
91       mCORSMode(aCORSMode),
92       mIntegrity(aIntegrity),
93       mReferrerPolicy(mozilla::net::RP_Default)
94   {
95   }
96 
97   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsScriptLoadRequest)98   NS_DECL_CYCLE_COLLECTION_CLASS(nsScriptLoadRequest)
99 
100   bool IsModuleRequest() const
101   {
102     return mKind == nsScriptKind::Module;
103   }
104 
105   nsModuleLoadRequest* AsModuleRequest();
106 
FireScriptAvailable(nsresult aResult)107   void FireScriptAvailable(nsresult aResult)
108   {
109     mElement->ScriptAvailable(aResult, mElement, mIsInline, mURI, mLineNo);
110   }
FireScriptEvaluated(nsresult aResult)111   void FireScriptEvaluated(nsresult aResult)
112   {
113     mElement->ScriptEvaluated(aResult, mElement, mIsInline);
114   }
115 
IsPreload()116   bool IsPreload()
117   {
118     return mElement == nullptr;
119   }
120 
121   virtual void Cancel();
122 
IsCanceled()123   bool IsCanceled() const
124   {
125     return mIsCanceled;
126   }
127 
128   virtual void SetReady();
129 
OffThreadTokenPtr()130   void** OffThreadTokenPtr()
131   {
132     return mOffThreadToken ?  &mOffThreadToken : nullptr;
133   }
134 
135   enum class Progress {
136     Loading,
137     Compiling,
138     FetchingImports,
139     Ready
140   };
IsReadyToRun()141   bool IsReadyToRun() const {
142     return mProgress == Progress::Ready;
143   }
IsLoading()144   bool IsLoading() const {
145     return mProgress == Progress::Loading;
146   }
InCompilingStage()147   bool InCompilingStage() const {
148     return mProgress == Progress::Compiling ||
149            (IsReadyToRun() && mWasCompiledOMT);
150   }
151 
152   void MaybeCancelOffThreadScript();
153 
154   using super::getNext;
155   using super::isInList;
156 
157   const nsScriptKind mKind;
158   nsCOMPtr<nsIScriptElement> mElement;
159   Progress mProgress;     // Are we still waiting for a load to complete?
160   bool mIsInline;         // Is the script inline or loaded?
161   bool mHasSourceMapURL;  // Does the HTTP header have a source map url?
162   bool mIsDefer;          // True if we live in mDeferRequests.
163   bool mIsAsync;          // True if we live in mLoadingAsyncRequests or mLoadedAsyncRequests.
164   bool mIsNonAsyncScriptInserted; // True if we live in mNonAsyncExternalScriptInsertedRequests
165   bool mIsXSLT;           // True if we live in mXSLTRequests.
166   bool mIsCanceled;       // True if we have been explicitly canceled.
167   bool mWasCompiledOMT;   // True if the script has been compiled off main thread.
168   void* mOffThreadToken;  // Off-thread parsing token.
169   nsString mSourceMapURL; // Holds source map url for loaded scripts
170   char16_t* mScriptTextBuf; // Holds script text for non-inline scripts. Don't
171   size_t mScriptTextLength; // use nsString so we can give ownership to jsapi.
172   uint32_t mJSVersion;
173   nsCOMPtr<nsIURI> mURI;
174   nsCOMPtr<nsIPrincipal> mOriginPrincipal;
175   nsAutoCString mURL;     // Keep the URI's filename alive during off thread parsing.
176   int32_t mLineNo;
177   const mozilla::CORSMode mCORSMode;
178   const mozilla::dom::SRIMetadata mIntegrity;
179   mozilla::net::ReferrerPolicy mReferrerPolicy;
180 };
181 
182 class nsScriptLoadRequestList : private mozilla::LinkedList<nsScriptLoadRequest>
183 {
184   typedef mozilla::LinkedList<nsScriptLoadRequest> super;
185 
186 public:
187   ~nsScriptLoadRequestList();
188 
189   void Clear();
190 
191 #ifdef DEBUG
192   bool Contains(nsScriptLoadRequest* aElem) const;
193 #endif // DEBUG
194 
195   using super::getFirst;
196   using super::isEmpty;
197 
AppendElement(nsScriptLoadRequest * aElem)198   void AppendElement(nsScriptLoadRequest* aElem)
199   {
200     MOZ_ASSERT(!aElem->isInList());
201     NS_ADDREF(aElem);
202     insertBack(aElem);
203   }
204 
205   MOZ_MUST_USE
Steal(nsScriptLoadRequest * aElem)206   already_AddRefed<nsScriptLoadRequest> Steal(nsScriptLoadRequest* aElem)
207   {
208     aElem->removeFrom(*this);
209     return dont_AddRef(aElem);
210   }
211 
212   MOZ_MUST_USE
StealFirst()213   already_AddRefed<nsScriptLoadRequest> StealFirst()
214   {
215     MOZ_ASSERT(!isEmpty());
216     return Steal(getFirst());
217   }
218 
Remove(nsScriptLoadRequest * aElem)219   void Remove(nsScriptLoadRequest* aElem)
220   {
221     aElem->removeFrom(*this);
222     NS_RELEASE(aElem);
223   }
224 };
225 
226 //////////////////////////////////////////////////////////////
227 // Script loader implementation
228 //////////////////////////////////////////////////////////////
229 
230 class nsScriptLoader final : public nsISupports
231 {
232   class MOZ_STACK_CLASS AutoCurrentScriptUpdater
233   {
234   public:
AutoCurrentScriptUpdater(nsScriptLoader * aScriptLoader,nsIScriptElement * aCurrentScript)235     AutoCurrentScriptUpdater(nsScriptLoader* aScriptLoader,
236                              nsIScriptElement* aCurrentScript)
237       : mOldScript(aScriptLoader->mCurrentScript)
238       , mScriptLoader(aScriptLoader)
239     {
240       mScriptLoader->mCurrentScript = aCurrentScript;
241     }
~AutoCurrentScriptUpdater()242     ~AutoCurrentScriptUpdater()
243     {
244       mScriptLoader->mCurrentScript.swap(mOldScript);
245     }
246   private:
247     nsCOMPtr<nsIScriptElement> mOldScript;
248     nsScriptLoader* mScriptLoader;
249   };
250 
251   friend class nsModuleLoadRequest;
252   friend class nsScriptRequestProcessor;
253   friend class nsScriptLoadHandler;
254   friend class AutoCurrentScriptUpdater;
255 
256 public:
257   explicit nsScriptLoader(nsIDocument* aDocument);
258 
259   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsScriptLoader)260   NS_DECL_CYCLE_COLLECTION_CLASS(nsScriptLoader)
261 
262   /**
263    * The loader maintains a weak reference to the document with
264    * which it is initialized. This call forces the reference to
265    * be dropped.
266    */
267   void DropDocumentReference()
268   {
269     mDocument = nullptr;
270   }
271 
272   /**
273    * Add an observer for all scripts loaded through this loader.
274    *
275    * @param aObserver observer for all script processing.
276    */
AddObserver(nsIScriptLoaderObserver * aObserver)277   nsresult AddObserver(nsIScriptLoaderObserver* aObserver)
278   {
279     return mObservers.AppendObject(aObserver) ? NS_OK :
280       NS_ERROR_OUT_OF_MEMORY;
281   }
282 
283   /**
284    * Remove an observer.
285    *
286    * @param aObserver observer to be removed
287    */
RemoveObserver(nsIScriptLoaderObserver * aObserver)288   void RemoveObserver(nsIScriptLoaderObserver* aObserver)
289   {
290     mObservers.RemoveObject(aObserver);
291   }
292 
293   /**
294    * Process a script element. This will include both loading the
295    * source of the element if it is not inline and evaluating
296    * the script itself.
297    *
298    * If the script is an inline script that can be executed immediately
299    * (i.e. there are no other scripts pending) then ScriptAvailable
300    * and ScriptEvaluated will be called before the function returns.
301    *
302    * If true is returned the script could not be executed immediately.
303    * In this case ScriptAvailable is guaranteed to be called at a later
304    * point (as well as possibly ScriptEvaluated).
305    *
306    * @param aElement The element representing the script to be loaded and
307    *        evaluated.
308    */
309   bool ProcessScriptElement(nsIScriptElement* aElement);
310 
311   /**
312    * Gets the currently executing script. This is useful if you want to
313    * generate a unique key based on the currently executing script.
314    */
GetCurrentScript()315   nsIScriptElement* GetCurrentScript()
316   {
317     return mCurrentScript;
318   }
319 
GetCurrentParserInsertedScript()320   nsIScriptElement* GetCurrentParserInsertedScript()
321   {
322     return mCurrentParserInsertedScript;
323   }
324 
325   /**
326    * Whether the loader is enabled or not.
327    * When disabled, processing of new script elements is disabled.
328    * Any call to ProcessScriptElement() will return false. Note that
329    * this DOES NOT disable currently loading or executing scripts.
330    */
GetEnabled()331   bool GetEnabled()
332   {
333     return mEnabled;
334   }
SetEnabled(bool aEnabled)335   void SetEnabled(bool aEnabled)
336   {
337     if (!mEnabled && aEnabled) {
338       ProcessPendingRequestsAsync();
339     }
340     mEnabled = aEnabled;
341   }
342 
343   /**
344    * Add/remove a blocker for parser-blocking scripts (and XSLT
345    * scripts). Blockers will stop such scripts from executing, but not from
346    * loading.
347    */
AddParserBlockingScriptExecutionBlocker()348   void AddParserBlockingScriptExecutionBlocker()
349   {
350     ++mParserBlockingBlockerCount;
351   }
RemoveParserBlockingScriptExecutionBlocker()352   void RemoveParserBlockingScriptExecutionBlocker()
353   {
354     if (!--mParserBlockingBlockerCount && ReadyToExecuteScripts()) {
355       ProcessPendingRequestsAsync();
356     }
357   }
358 
359   /**
360    * Add/remove a blocker for execution of all scripts.  Blockers will stop
361    * scripts from executing, but not from loading.
362    */
AddExecuteBlocker()363   void AddExecuteBlocker()
364   {
365     ++mBlockerCount;
366   }
RemoveExecuteBlocker()367   void RemoveExecuteBlocker()
368   {
369     MOZ_ASSERT(mBlockerCount);
370     if (!--mBlockerCount) {
371       ProcessPendingRequestsAsync();
372     }
373   }
374 
375   /**
376    * Convert the given buffer to a UTF-16 string.
377    * @param aChannel     Channel corresponding to the data. May be null.
378    * @param aData        The data to convert
379    * @param aLength      Length of the data
380    * @param aHintCharset Hint for the character set (e.g., from a charset
381    *                     attribute). May be the empty string.
382    * @param aDocument    Document which the data is loaded for. Must not be
383    *                     null.
384    * @param aBufOut      [out] char16_t array allocated by ConvertToUTF16 and
385    *                     containing data converted to unicode.  Caller must
386    *                     js_free() this data when no longer needed.
387    * @param aLengthOut   [out] Length of array returned in aBufOut in number
388    *                     of char16_t code units.
389    */
390   static nsresult ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
391                                  uint32_t aLength,
392                                  const nsAString& aHintCharset,
393                                  nsIDocument* aDocument,
394                                  char16_t*& aBufOut, size_t& aLengthOut);
395 
396   /**
397    * Handle the completion of a stream.  This is called by the
398    * nsScriptLoadHandler object which observes the IncrementalStreamLoader
399    * loading the script.
400    */
401   nsresult OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
402                             nsISupports* aContext,
403                             nsresult aChannelStatus,
404                             nsresult aSRIStatus,
405                             mozilla::Vector<char16_t> &aString,
406                             mozilla::dom::SRICheckDataVerifier* aSRIDataVerifier);
407 
408   /**
409    * Processes any pending requests that are ready for processing.
410    */
411   void ProcessPendingRequests();
412 
413   /**
414    * Starts deferring deferred scripts and puts them in the mDeferredRequests
415    * queue instead.
416    */
BeginDeferringScripts()417   void BeginDeferringScripts()
418   {
419     mDeferEnabled = true;
420     if (mDocument) {
421       mDocument->BlockOnload();
422     }
423   }
424 
425   /**
426    * Notifies the script loader that parsing is done.  If aTerminated is true,
427    * this will drop any pending scripts that haven't run yet.  Otherwise, it
428    * will stops deferring scripts and immediately processes the
429    * mDeferredRequests queue.
430    *
431    * WARNING: This function will synchronously execute content scripts, so be
432    * prepared that the world might change around you.
433    */
434   void ParsingComplete(bool aTerminated);
435 
436   /**
437    * Returns the number of pending scripts, deferred or not.
438    */
HasPendingOrCurrentScripts()439   uint32_t HasPendingOrCurrentScripts()
440   {
441     return mCurrentScript || mParserBlockingRequest;
442   }
443 
444   /**
445    * Adds aURI to the preload list and starts loading it.
446    *
447    * @param aURI The URI of the external script.
448    * @param aCharset The charset parameter for the script.
449    * @param aType The type parameter for the script.
450    * @param aCrossOrigin The crossorigin attribute for the script.
451    *                     Void if not present.
452    * @param aIntegrity The expect hash url, if avail, of the request
453    * @param aScriptFromHead Whether or not the script was a child of head
454    */
455   virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
456                           const nsAString &aType,
457                           const nsAString &aCrossOrigin,
458                           const nsAString& aIntegrity,
459                           bool aScriptFromHead,
460                           const mozilla::net::ReferrerPolicy aReferrerPolicy);
461 
462   /**
463    * Process a request that was deferred so that the script could be compiled
464    * off thread.
465    */
466   nsresult ProcessOffThreadRequest(nsScriptLoadRequest *aRequest);
467 
AddPendingChildLoader(nsScriptLoader * aChild)468   bool AddPendingChildLoader(nsScriptLoader* aChild) {
469     return mPendingChildLoaders.AppendElement(aChild) != nullptr;
470   }
471 
472 private:
473   virtual ~nsScriptLoader();
474 
475   nsScriptLoadRequest* CreateLoadRequest(
476     nsScriptKind aKind,
477     nsIScriptElement* aElement,
478     uint32_t aVersion,
479     mozilla::CORSMode aCORSMode,
480     const mozilla::dom::SRIMetadata &aIntegrity);
481 
482   /**
483    * Unblocks the creator parser of the parser-blocking scripts.
484    */
485   void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest);
486 
487   /**
488    * Asynchronously resumes the creator parser of the parser-blocking scripts.
489    */
490   void ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest);
491 
492 
493   /**
494    * Helper function to check the content policy for a given request.
495    */
496   static nsresult CheckContentPolicy(nsIDocument* aDocument,
497                                      nsISupports *aContext,
498                                      nsIURI *aURI,
499                                      const nsAString &aType,
500                                      bool aIsPreLoad);
501 
502   /**
503    * Start a load for aRequest's URI.
504    */
505   nsresult StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
506                      bool aScriptFromHead);
507 
508   /**
509    * Process any pending requests asynchronously (i.e. off an event) if there
510    * are any. Note that this is a no-op if there aren't any currently pending
511    * requests.
512    *
513    * This function is virtual to allow cross-library calls to SetEnabled()
514    */
515   virtual void ProcessPendingRequestsAsync();
516 
517   /**
518    * If true, the loader is ready to execute parser-blocking scripts, and so are
519    * all its ancestors.  If the loader itself is ready but some ancestor is not,
520    * this function will add an execute blocker and ask the ancestor to remove it
521    * once it becomes ready.
522    */
523   bool ReadyToExecuteParserBlockingScripts();
524 
525   /**
526    * Return whether just this loader is ready to execute parser-blocking
527    * scripts.
528    */
SelfReadyToExecuteParserBlockingScripts()529   bool SelfReadyToExecuteParserBlockingScripts()
530   {
531     return ReadyToExecuteScripts() && !mParserBlockingBlockerCount;
532   }
533 
534   /**
535    * Return whether this loader is ready to execute scripts in general.
536    */
ReadyToExecuteScripts()537   bool ReadyToExecuteScripts()
538   {
539     return mEnabled && !mBlockerCount;
540   }
541 
542   nsresult AttemptAsyncScriptCompile(nsScriptLoadRequest* aRequest);
543   nsresult ProcessRequest(nsScriptLoadRequest* aRequest);
544   nsresult CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest);
545   void FireScriptAvailable(nsresult aResult,
546                            nsScriptLoadRequest* aRequest);
547   void FireScriptEvaluated(nsresult aResult,
548                            nsScriptLoadRequest* aRequest);
549   nsresult EvaluateScript(nsScriptLoadRequest* aRequest);
550 
551   already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalObject();
552   nsresult FillCompileOptionsForRequest(const mozilla::dom::AutoJSAPI& jsapi,
553                                         nsScriptLoadRequest* aRequest,
554                                         JS::Handle<JSObject*> aScopeChain,
555                                         JS::CompileOptions* aOptions);
556 
557   uint32_t NumberOfProcessors();
558   nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
559                                 nsIIncrementalStreamLoader* aLoader,
560                                 nsresult aStatus,
561                                 mozilla::Vector<char16_t> &aString);
562 
563   void AddDeferRequest(nsScriptLoadRequest* aRequest);
564   bool MaybeRemovedDeferRequests();
565 
566   void MaybeMoveToLoadedList(nsScriptLoadRequest* aRequest);
567 
568   JS::SourceBufferHolder GetScriptSource(nsScriptLoadRequest* aRequest,
569                                          nsAutoString& inlineData);
570 
571   void SetModuleFetchStarted(nsModuleLoadRequest *aRequest);
572   void SetModuleFetchFinishedAndResumeWaitingRequests(nsModuleLoadRequest *aRequest,
573                                                       nsresult aResult);
574 
575   bool IsFetchingModule(nsModuleLoadRequest *aRequest) const;
576 
577   bool ModuleMapContainsModule(nsModuleLoadRequest *aRequest) const;
578   RefPtr<mozilla::GenericPromise> WaitForModuleFetch(nsModuleLoadRequest *aRequest);
579   nsModuleScript* GetFetchedModule(nsIURI* aURL) const;
580 
581   friend bool
582   HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp);
583 
584   nsresult CreateModuleScript(nsModuleLoadRequest* aRequest);
585   nsresult ProcessFetchedModuleSource(nsModuleLoadRequest* aRequest);
586   void ProcessLoadedModuleTree(nsModuleLoadRequest* aRequest);
587   bool InstantiateModuleTree(nsModuleLoadRequest* aRequest);
588   void StartFetchingModuleDependencies(nsModuleLoadRequest* aRequest);
589 
590   RefPtr<mozilla::GenericPromise>
591   StartFetchingModuleAndDependencies(nsModuleLoadRequest* aRequest, nsIURI* aURI);
592 
593   nsIDocument* mDocument;                   // [WEAK]
594   nsCOMArray<nsIScriptLoaderObserver> mObservers;
595   nsScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests;
596   // mLoadingAsyncRequests holds async requests while they're loading; when they
597   // have been loaded they are moved to mLoadedAsyncRequests.
598   nsScriptLoadRequestList mLoadingAsyncRequests;
599   nsScriptLoadRequestList mLoadedAsyncRequests;
600   nsScriptLoadRequestList mDeferRequests;
601   nsScriptLoadRequestList mXSLTRequests;
602   RefPtr<nsScriptLoadRequest> mParserBlockingRequest;
603 
604   // In mRequests, the additional information here is stored by the element.
605   struct PreloadInfo {
606     RefPtr<nsScriptLoadRequest> mRequest;
607     nsString mCharset;
608   };
609 
610   friend void ImplCycleCollectionUnlink(nsScriptLoader::PreloadInfo& aField);
611   friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
612                                           nsScriptLoader::PreloadInfo& aField,
613                                           const char* aName, uint32_t aFlags);
614 
615   struct PreloadRequestComparator {
EqualsPreloadRequestComparator616     bool Equals(const PreloadInfo &aPi, nsScriptLoadRequest * const &aRequest)
617         const
618     {
619       return aRequest == aPi.mRequest;
620     }
621   };
622   struct PreloadURIComparator {
623     bool Equals(const PreloadInfo &aPi, nsIURI * const &aURI) const;
624   };
625   nsTArray<PreloadInfo> mPreloads;
626 
627   nsCOMPtr<nsIScriptElement> mCurrentScript;
628   nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
629   nsTArray< RefPtr<nsScriptLoader> > mPendingChildLoaders;
630   uint32_t mParserBlockingBlockerCount;
631   uint32_t mBlockerCount;
632   uint32_t mNumberOfProcessors;
633   bool mEnabled;
634   bool mDeferEnabled;
635   bool mDocumentParsingDone;
636   bool mBlockingDOMContentLoaded;
637 
638   // Module map
639   nsRefPtrHashtable<nsURIHashKey, mozilla::GenericPromise::Private> mFetchingModules;
640   nsRefPtrHashtable<nsURIHashKey, nsModuleScript> mFetchedModules;
641 
642   nsCOMPtr<nsIConsoleReportCollector> mReporter;
643 };
644 
645 class nsScriptLoadHandler final : public nsIIncrementalStreamLoaderObserver
646 {
647 public:
648   explicit nsScriptLoadHandler(nsScriptLoader* aScriptLoader,
649                                nsScriptLoadRequest *aRequest,
650                                mozilla::dom::SRICheckDataVerifier *aSRIDataVerifier);
651 
652   NS_DECL_ISUPPORTS
653   NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
654 
655 private:
656   virtual ~nsScriptLoadHandler();
657 
658   /*
659    * Try to decode some raw data.
660    */
661   nsresult TryDecodeRawData(const uint8_t* aData, uint32_t aDataLength,
662                             bool aEndOfStream);
663 
664   /*
665    * Discover the charset by looking at the stream data, the script
666    * tag, and other indicators.  Returns true if charset has been
667    * discovered.
668    */
669   bool EnsureDecoder(nsIIncrementalStreamLoader *aLoader,
670                      const uint8_t* aData, uint32_t aDataLength,
671                      bool aEndOfStream);
672 
673   // ScriptLoader which will handle the parsed script.
674   RefPtr<nsScriptLoader>        mScriptLoader;
675 
676   // The nsScriptLoadRequest for this load.
677   RefPtr<nsScriptLoadRequest>   mRequest;
678 
679   // SRI data verifier.
680   nsAutoPtr<mozilla::dom::SRICheckDataVerifier> mSRIDataVerifier;
681 
682   // Status of SRI data operations.
683   nsresult                      mSRIStatus;
684 
685   // Unicode decoder for charset.
686   nsCOMPtr<nsIUnicodeDecoder>   mDecoder;
687 
688   // Accumulated decoded char buffer.
689   mozilla::Vector<char16_t>     mBuffer;
690 };
691 
692 class nsAutoScriptLoaderDisabler
693 {
694 public:
nsAutoScriptLoaderDisabler(nsIDocument * aDoc)695   explicit nsAutoScriptLoaderDisabler(nsIDocument* aDoc)
696   {
697     mLoader = aDoc->ScriptLoader();
698     mWasEnabled = mLoader->GetEnabled();
699     if (mWasEnabled) {
700       mLoader->SetEnabled(false);
701     }
702   }
703 
~nsAutoScriptLoaderDisabler()704   ~nsAutoScriptLoaderDisabler()
705   {
706     if (mWasEnabled) {
707       mLoader->SetEnabled(true);
708     }
709   }
710 
711   bool mWasEnabled;
712   RefPtr<nsScriptLoader> mLoader;
713 };
714 
715 #endif //__nsScriptLoader_h__
716