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 #ifndef mozilla_dom_ScriptLoader_h 8 #define mozilla_dom_ScriptLoader_h 9 10 #include "nsCOMPtr.h" 11 #include "nsRefPtrHashtable.h" 12 #include "mozilla/Encoding.h" 13 #include "nsIScriptElement.h" 14 #include "nsCOMArray.h" 15 #include "nsCycleCollectionParticipant.h" 16 #include "nsTArray.h" 17 #include "mozilla/dom/Document.h" 18 #include "nsIIncrementalStreamLoader.h" 19 #include "nsURIHashKey.h" 20 #include "mozilla/CORSMode.h" 21 #include "mozilla/dom/ScriptLoadRequest.h" 22 #include "mozilla/dom/SRIMetadata.h" 23 #include "mozilla/dom/SRICheck.h" 24 #include "mozilla/MaybeOneOf.h" 25 #include "mozilla/MozPromise.h" 26 #include "mozilla/Utf8.h" // mozilla::Utf8Unit 27 #include "mozilla/Vector.h" 28 #include "ScriptKind.h" 29 30 class nsIURI; 31 32 namespace JS { 33 34 template <typename UnitT> 35 class SourceText; 36 37 } // namespace JS 38 39 namespace mozilla { 40 namespace dom { 41 42 class AutoJSAPI; 43 class LoadedScript; 44 class ModuleLoadRequest; 45 class ModuleScript; 46 class ScriptLoadHandler; 47 class ScriptRequestProcessor; 48 49 ////////////////////////////////////////////////////////////// 50 // Script loader implementation 51 ////////////////////////////////////////////////////////////// 52 53 class ScriptLoader final : public nsISupports { 54 class MOZ_STACK_CLASS AutoCurrentScriptUpdater { 55 public: AutoCurrentScriptUpdater(ScriptLoader * aScriptLoader,nsIScriptElement * aCurrentScript)56 AutoCurrentScriptUpdater(ScriptLoader* aScriptLoader, 57 nsIScriptElement* aCurrentScript) 58 : mOldScript(aScriptLoader->mCurrentScript), 59 mScriptLoader(aScriptLoader) { 60 nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentScript); 61 mScriptLoader->mCurrentScript = 62 node && !node->IsInShadowTree() ? aCurrentScript : nullptr; 63 } 64 ~AutoCurrentScriptUpdater()65 ~AutoCurrentScriptUpdater() { 66 mScriptLoader->mCurrentScript.swap(mOldScript); 67 } 68 69 private: 70 nsCOMPtr<nsIScriptElement> mOldScript; 71 ScriptLoader* mScriptLoader; 72 }; 73 74 friend class ModuleLoadRequest; 75 friend class ScriptRequestProcessor; 76 friend class ScriptLoadHandler; 77 friend class AutoCurrentScriptUpdater; 78 79 public: 80 explicit ScriptLoader(Document* aDocument); 81 82 NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(ScriptLoader)83 NS_DECL_CYCLE_COLLECTION_CLASS(ScriptLoader) 84 85 /** 86 * The loader maintains a weak reference to the document with 87 * which it is initialized. This call forces the reference to 88 * be dropped. 89 */ 90 void DropDocumentReference() { mDocument = nullptr; } 91 92 /** 93 * Add an observer for all scripts loaded through this loader. 94 * 95 * @param aObserver observer for all script processing. 96 */ AddObserver(nsIScriptLoaderObserver * aObserver)97 nsresult AddObserver(nsIScriptLoaderObserver* aObserver) { 98 return mObservers.AppendObject(aObserver) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; 99 } 100 101 /** 102 * Remove an observer. 103 * 104 * @param aObserver observer to be removed 105 */ RemoveObserver(nsIScriptLoaderObserver * aObserver)106 void RemoveObserver(nsIScriptLoaderObserver* aObserver) { 107 mObservers.RemoveObject(aObserver); 108 } 109 110 /** 111 * Process a script element. This will include both loading the 112 * source of the element if it is not inline and evaluating 113 * the script itself. 114 * 115 * If the script is an inline script that can be executed immediately 116 * (i.e. there are no other scripts pending) then ScriptAvailable 117 * and ScriptEvaluated will be called before the function returns. 118 * 119 * If true is returned the script could not be executed immediately. 120 * In this case ScriptAvailable is guaranteed to be called at a later 121 * point (as well as possibly ScriptEvaluated). 122 * 123 * @param aElement The element representing the script to be loaded and 124 * evaluated. 125 */ 126 bool ProcessScriptElement(nsIScriptElement* aElement); 127 128 /** 129 * Gets the currently executing script. This is useful if you want to 130 * generate a unique key based on the currently executing script. 131 */ GetCurrentScript()132 nsIScriptElement* GetCurrentScript() { return mCurrentScript; } 133 GetCurrentParserInsertedScript()134 nsIScriptElement* GetCurrentParserInsertedScript() { 135 return mCurrentParserInsertedScript; 136 } 137 138 /** 139 * Whether the loader is enabled or not. 140 * When disabled, processing of new script elements is disabled. 141 * Any call to ProcessScriptElement() will return false. Note that 142 * this DOES NOT disable currently loading or executing scripts. 143 */ GetEnabled()144 bool GetEnabled() { return mEnabled; } 145 SetEnabled(bool aEnabled)146 void SetEnabled(bool aEnabled) { 147 if (!mEnabled && aEnabled) { 148 ProcessPendingRequestsAsync(); 149 } 150 mEnabled = aEnabled; 151 } 152 153 /** 154 * Add/remove a blocker for parser-blocking scripts (and XSLT 155 * scripts). Blockers will stop such scripts from executing, but not from 156 * loading. 157 */ AddParserBlockingScriptExecutionBlocker()158 void AddParserBlockingScriptExecutionBlocker() { 159 ++mParserBlockingBlockerCount; 160 } 161 RemoveParserBlockingScriptExecutionBlocker()162 void RemoveParserBlockingScriptExecutionBlocker() { 163 if (!--mParserBlockingBlockerCount && ReadyToExecuteScripts()) { 164 ProcessPendingRequestsAsync(); 165 } 166 } 167 168 /** 169 * Add/remove a blocker for execution of all scripts. Blockers will stop 170 * scripts from executing, but not from loading. 171 */ AddExecuteBlocker()172 void AddExecuteBlocker() { ++mBlockerCount; } 173 RemoveExecuteBlocker()174 void RemoveExecuteBlocker() { 175 MOZ_ASSERT(mBlockerCount); 176 if (!--mBlockerCount) { 177 ProcessPendingRequestsAsync(); 178 } 179 } 180 181 /** 182 * Convert the given buffer to a UTF-16 string. If the buffer begins with a 183 * BOM, it is interpreted as that encoding; otherwise the first of |aChannel|, 184 * |aHintCharset|, or |aDocument| that provides a recognized encoding is used, 185 * or Windows-1252 if none of them do. 186 * 187 * Encoding errors in the buffer are converted to replacement characters, so 188 * allocation failure is the only way this function can fail. 189 * 190 * @param aChannel Channel corresponding to the data. May be null. 191 * @param aData The data to convert 192 * @param aLength Length of the data 193 * @param aHintCharset Character set hint (e.g., from a charset attribute). 194 * @param aDocument Document which the data is loaded for. May be null. 195 * @param aBufOut [out] fresh char16_t array containing data converted to 196 * Unicode. Caller must js_free() this data when finished 197 * with it. 198 * @param aLengthOut [out] Length of array returned in aBufOut in number 199 * of char16_t code units. 200 */ 201 static nsresult ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData, 202 uint32_t aLength, 203 const nsAString& aHintCharset, 204 Document* aDocument, char16_t*& aBufOut, 205 size_t& aLengthOut); 206 ConvertToUTF16(nsIChannel * aChannel,const uint8_t * aData,uint32_t aLength,const nsAString & aHintCharset,Document * aDocument,JS::UniqueTwoByteChars & aBufOut,size_t & aLengthOut)207 static inline nsresult ConvertToUTF16(nsIChannel* aChannel, 208 const uint8_t* aData, uint32_t aLength, 209 const nsAString& aHintCharset, 210 Document* aDocument, 211 JS::UniqueTwoByteChars& aBufOut, 212 size_t& aLengthOut) { 213 char16_t* bufOut; 214 nsresult rv = ConvertToUTF16(aChannel, aData, aLength, aHintCharset, 215 aDocument, bufOut, aLengthOut); 216 if (NS_SUCCEEDED(rv)) { 217 aBufOut.reset(bufOut); 218 } 219 return rv; 220 }; 221 222 /** 223 * Convert the given buffer to a UTF-8 string. If the buffer begins with a 224 * BOM, it is interpreted as that encoding; otherwise the first of |aChannel|, 225 * |aHintCharset|, or |aDocument| that provides a recognized encoding is used, 226 * or Windows-1252 if none of them do. 227 * 228 * Encoding errors in the buffer are converted to replacement characters, so 229 * allocation failure is the only way this function can fail. 230 * 231 * @param aChannel Channel corresponding to the data. May be null. 232 * @param aData The data to convert 233 * @param aLength Length of the data 234 * @param aHintCharset Character set hint (e.g., from a charset attribute). 235 * @param aDocument Document which the data is loaded for. May be null. 236 * @param aBufOut [out] fresh Utf8Unit array containing data converted to 237 * Unicode. Caller must js_free() this data when finished 238 * with it. 239 * @param aLengthOut [out] Length of array returned in aBufOut in UTF-8 code 240 * units (i.e. in bytes). 241 */ 242 static nsresult ConvertToUTF8(nsIChannel* aChannel, const uint8_t* aData, 243 uint32_t aLength, const nsAString& aHintCharset, 244 Document* aDocument, Utf8Unit*& aBufOut, 245 size_t& aLengthOut); 246 247 /** 248 * Handle the completion of a stream. This is called by the 249 * ScriptLoadHandler object which observes the IncrementalStreamLoader 250 * loading the script. The streamed content is expected to be stored on the 251 * aRequest argument. 252 */ 253 nsresult OnStreamComplete(nsIIncrementalStreamLoader* aLoader, 254 ScriptLoadRequest* aRequest, 255 nsresult aChannelStatus, nsresult aSRIStatus, 256 SRICheckDataVerifier* aSRIDataVerifier); 257 258 /** 259 * Returns wether any request is queued, and not executed yet. 260 */ 261 bool HasPendingRequests(); 262 263 /** 264 * Processes any pending requests that are ready for processing. 265 */ 266 void ProcessPendingRequests(); 267 268 /** 269 * Starts deferring deferred scripts and puts them in the mDeferredRequests 270 * queue instead. 271 */ BeginDeferringScripts()272 void BeginDeferringScripts() { 273 mDeferEnabled = true; 274 if (mDeferCheckpointReached) { 275 // We already completed a parse and were just waiting for some async 276 // scripts to load (and were already blocking the load event waiting for 277 // that to happen), when document.open() happened and now we're doing a 278 // new parse. We shouldn't block the load event again, but _should_ reset 279 // mDeferCheckpointReached to false. It'll get set to true again when the 280 // DeferCheckpointReached call that corresponds to this 281 // BeginDeferringScripts call happens (on document.close()), since we just 282 // set mDeferEnabled to true. 283 mDeferCheckpointReached = false; 284 } else { 285 if (mDocument) { 286 mDocument->BlockOnload(); 287 } 288 } 289 } 290 291 /** 292 * Notifies the script loader that parsing is done. If aTerminated is true, 293 * this will drop any pending scripts that haven't run yet, otherwise it will 294 * do nothing. 295 */ 296 void ParsingComplete(bool aTerminated); 297 298 /** 299 * Notifies the script loader that the checkpoint to begin execution of defer 300 * scripts has been reached. This is either the end of of the document parse 301 * or the end of loading of parser-inserted stylesheets, whatever happens 302 * last. 303 * 304 * Otherwise, it will stop deferring scripts and immediately processes the 305 * mDeferredRequests queue. 306 * 307 * WARNING: This function will synchronously execute content scripts, so be 308 * prepared that the world might change around you. 309 */ 310 void DeferCheckpointReached(); 311 312 /** 313 * Returns the number of pending scripts, deferred or not. 314 */ HasPendingOrCurrentScripts()315 uint32_t HasPendingOrCurrentScripts() { 316 return mCurrentScript || mParserBlockingRequest; 317 } 318 319 /** 320 * Adds aURI to the preload list and starts loading it. 321 * 322 * @param aURI The URI of the external script. 323 * @param aCharset The charset parameter for the script. 324 * @param aType The type parameter for the script. 325 * @param aCrossOrigin The crossorigin attribute for the script. 326 * Void if not present. 327 * @param aIntegrity The expect hash url, if avail, of the request 328 * @param aScriptFromHead Whether or not the script was a child of head 329 */ 330 virtual void PreloadURI(nsIURI* aURI, const nsAString& aCharset, 331 const nsAString& aType, const nsAString& aCrossOrigin, 332 const nsAString& aIntegrity, bool aScriptFromHead, 333 bool aAsync, bool aDefer, bool aNoModule, 334 bool aLinkPreload, 335 const ReferrerPolicy aReferrerPolicy); 336 337 /** 338 * Process a request that was deferred so that the script could be compiled 339 * off thread. 340 */ 341 nsresult ProcessOffThreadRequest(ScriptLoadRequest* aRequest); 342 AddPendingChildLoader(ScriptLoader * aChild)343 bool AddPendingChildLoader(ScriptLoader* aChild) { 344 // XXX(Bug 1631371) Check if this should use a fallible operation as it 345 // pretended earlier. Else, change the return type to void. 346 mPendingChildLoaders.AppendElement(aChild); 347 return true; 348 } 349 GetDocGroup()350 mozilla::dom::DocGroup* GetDocGroup() const { 351 return mDocument->GetDocGroup(); 352 } 353 354 /** 355 * Register the fact that we saw the load event, and that we need to save the 356 * bytecode at the next loop cycle unless new scripts are waiting in the 357 * pipeline. 358 */ 359 void LoadEventFired(); 360 361 /** 362 * Destroy and prevent the ScriptLoader or the ScriptLoadRequests from owning 363 * any references to the JSScript or to the Request which might be used for 364 * caching the encoded bytecode. 365 */ Destroy()366 void Destroy() { GiveUpBytecodeEncoding(); } 367 368 /** 369 * Implement the HostResolveImportedModule abstract operation. 370 * 371 * Resolve a module specifier string and look this up in the module 372 * map, returning the result. This is only called for previously 373 * loaded modules and always succeeds. 374 * 375 * @param aReferencingPrivate A JS::Value which is either undefined 376 * or contains a LoadedScript private pointer. 377 * @param aSpecifier The module specifier. 378 * @param aModuleOut This is set to the module found. 379 */ 380 static void ResolveImportedModule(JSContext* aCx, 381 JS::Handle<JS::Value> aReferencingPrivate, 382 JS::Handle<JSString*> aSpecifier, 383 JS::MutableHandle<JSObject*> aModuleOut); 384 385 void StartDynamicImport(ModuleLoadRequest* aRequest); 386 void FinishDynamicImport(ModuleLoadRequest* aRequest, nsresult aResult); 387 void FinishDynamicImport(JSContext* aCx, ModuleLoadRequest* aRequest, 388 nsresult aResult); 389 390 /* 391 * Get the currently active script. This is used as the initiating script when 392 * executing timeout handler scripts. 393 */ 394 static LoadedScript* GetActiveScript(JSContext* aCx); 395 GetDocument()396 Document* GetDocument() const { return mDocument; } 397 398 private: 399 virtual ~ScriptLoader(); 400 401 void EnsureModuleHooksInitialized(); 402 403 ScriptLoadRequest* CreateLoadRequest(ScriptKind aKind, nsIURI* aURI, 404 nsIScriptElement* aElement, 405 nsIPrincipal* aTriggeringPrincipal, 406 mozilla::CORSMode aCORSMode, 407 const SRIMetadata& aIntegrity, 408 ReferrerPolicy aReferrerPolicy); 409 410 /** 411 * Unblocks the creator parser of the parser-blocking scripts. 412 */ 413 void UnblockParser(ScriptLoadRequest* aParserBlockingRequest); 414 415 /** 416 * Asynchronously resumes the creator parser of the parser-blocking scripts. 417 */ 418 void ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest); 419 420 bool ProcessExternalScript(nsIScriptElement* aElement, ScriptKind aScriptKind, 421 nsAutoString aTypeAttr, 422 nsIContent* aScriptContent); 423 424 bool ProcessInlineScript(nsIScriptElement* aElement, ScriptKind aScriptKind); 425 426 ScriptLoadRequest* LookupPreloadRequest(nsIScriptElement* aElement, 427 ScriptKind aScriptKind, 428 const SRIMetadata& aSRIMetadata); 429 430 void GetSRIMetadata(const nsAString& aIntegrityAttr, 431 SRIMetadata* aMetadataOut); 432 433 /** 434 * Given a script element, get the referrer policy should be applied to load 435 * requests. 436 */ 437 ReferrerPolicy GetReferrerPolicy(nsIScriptElement* aElement); 438 439 /** 440 * Helper function to check the content policy for a given request. 441 */ 442 static nsresult CheckContentPolicy(Document* aDocument, nsISupports* aContext, 443 const nsAString& aType, 444 ScriptLoadRequest* aRequest); 445 446 /** 447 * Helper function to determine whether an about: page loads a chrome: URI. 448 * Please note that this function only returns true if: 449 * * the about: page uses a ContentPrincipal with scheme about: 450 * * the about: page is not linkable from content 451 * (e.g. the function will return false for about:blank or about:srcdoc) 452 */ 453 static bool IsAboutPageLoadingChromeURI(ScriptLoadRequest* aRequest); 454 455 /** 456 * Start a load for aRequest's URI. 457 */ 458 nsresult StartLoad(ScriptLoadRequest* aRequest); 459 460 /** 461 * Abort the current stream, and re-start with a new load request from scratch 462 * without requesting any alternate data. Returns NS_BINDING_RETARGETED on 463 * success, as this error code is used to abort the input stream. 464 */ 465 nsresult RestartLoad(ScriptLoadRequest* aRequest); 466 467 void HandleLoadError(ScriptLoadRequest* aRequest, nsresult aResult); 468 469 /** 470 * Process any pending requests asynchronously (i.e. off an event) if there 471 * are any. Note that this is a no-op if there aren't any currently pending 472 * requests. 473 * 474 * This function is virtual to allow cross-library calls to SetEnabled() 475 */ 476 virtual void ProcessPendingRequestsAsync(); 477 478 /** 479 * If true, the loader is ready to execute parser-blocking scripts, and so are 480 * all its ancestors. If the loader itself is ready but some ancestor is not, 481 * this function will add an execute blocker and ask the ancestor to remove it 482 * once it becomes ready. 483 */ 484 bool ReadyToExecuteParserBlockingScripts(); 485 486 /** 487 * Return whether just this loader is ready to execute parser-blocking 488 * scripts. 489 */ SelfReadyToExecuteParserBlockingScripts()490 bool SelfReadyToExecuteParserBlockingScripts() { 491 return ReadyToExecuteScripts() && !mParserBlockingBlockerCount; 492 } 493 494 /** 495 * Return whether this loader is ready to execute scripts in general. 496 */ ReadyToExecuteScripts()497 bool ReadyToExecuteScripts() { return mEnabled && !mBlockerCount; } 498 499 nsresult VerifySRI(ScriptLoadRequest* aRequest, 500 nsIIncrementalStreamLoader* aLoader, nsresult aSRIStatus, 501 SRICheckDataVerifier* aSRIDataVerifier) const; 502 503 nsresult SaveSRIHash(ScriptLoadRequest* aRequest, 504 SRICheckDataVerifier* aSRIDataVerifier) const; 505 506 void ReportErrorToConsole(ScriptLoadRequest* aRequest, 507 nsresult aResult) const; 508 void ReportPreloadErrorsToConsole(ScriptLoadRequest* aRequest); 509 510 nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest, 511 bool* aCouldCompileOut); 512 nsresult ProcessRequest(ScriptLoadRequest* aRequest); 513 void ProcessDynamicImport(ModuleLoadRequest* aRequest); 514 nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest); 515 void FireScriptAvailable(nsresult aResult, ScriptLoadRequest* aRequest); 516 void FireScriptEvaluated(nsresult aResult, ScriptLoadRequest* aRequest); 517 nsresult EvaluateScript(ScriptLoadRequest* aRequest); 518 519 /** 520 * Queue the current script load request to be saved, when the page 521 * initialization ends. The page initialization end is defined as being the 522 * time when the load event got received, and when no more scripts are waiting 523 * to be executed. 524 */ 525 void RegisterForBytecodeEncoding(ScriptLoadRequest* aRequest); 526 527 /** 528 * Check if all conditions are met, i-e that the onLoad event fired and that 529 * no more script have to be processed. If all conditions are met, queue an 530 * event to encode all the bytecode and save them on the cache. 531 */ 532 void MaybeTriggerBytecodeEncoding(); 533 534 /** 535 * Iterate over all script load request and save the bytecode of executed 536 * functions on the cache provided by the channel. 537 */ 538 void EncodeBytecode(); 539 void EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest); 540 541 void GiveUpBytecodeEncoding(); 542 543 already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalObject(); 544 nsresult FillCompileOptionsForRequest(const mozilla::dom::AutoJSAPI& jsapi, 545 ScriptLoadRequest* aRequest, 546 JS::Handle<JSObject*> aScopeChain, 547 JS::CompileOptions* aOptions); 548 549 uint32_t NumberOfProcessors(); 550 nsresult PrepareLoadedRequest(ScriptLoadRequest* aRequest, 551 nsIIncrementalStreamLoader* aLoader, 552 nsresult aStatus); 553 554 void AddDeferRequest(ScriptLoadRequest* aRequest); 555 void AddAsyncRequest(ScriptLoadRequest* aRequest); 556 bool MaybeRemovedDeferRequests(); 557 558 void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest); 559 560 using MaybeSourceText = 561 mozilla::MaybeOneOf<JS::SourceText<char16_t>, JS::SourceText<Utf8Unit>>; 562 563 // Get source text. On success |aMaybeSource| will contain either UTF-8 or 564 // UTF-16 source; on failure it will remain in its initial state. 565 MOZ_MUST_USE nsresult GetScriptSource(JSContext* aCx, 566 ScriptLoadRequest* aRequest, 567 MaybeSourceText* aMaybeSource); 568 569 void SetModuleFetchStarted(ModuleLoadRequest* aRequest); 570 void SetModuleFetchFinishedAndResumeWaitingRequests( 571 ModuleLoadRequest* aRequest, nsresult aResult); 572 573 bool IsFetchingModule(ModuleLoadRequest* aRequest) const; 574 575 bool ModuleMapContainsURL(nsIURI* aURL) const; 576 RefPtr<mozilla::GenericNonExclusivePromise> WaitForModuleFetch(nsIURI* aURL); 577 ModuleScript* GetFetchedModule(nsIURI* aURL) const; 578 579 friend JSObject* HostResolveImportedModule( 580 JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate, 581 JS::Handle<JSString*> aSpecifier); 582 583 // Returns wether we should save the bytecode of this script after the 584 // execution of the script. 585 static bool ShouldCacheBytecode(ScriptLoadRequest* aRequest); 586 587 nsresult CreateModuleScript(ModuleLoadRequest* aRequest); 588 nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest); 589 void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest); 590 void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest); 591 bool InstantiateModuleTree(ModuleLoadRequest* aRequest); 592 JS::Value FindFirstParseError(ModuleLoadRequest* aRequest); 593 void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest); 594 595 RefPtr<mozilla::GenericPromise> StartFetchingModuleAndDependencies( 596 ModuleLoadRequest* aParent, nsIURI* aURI); 597 598 nsresult InitDebuggerDataForModuleTree(JSContext* aCx, 599 ModuleLoadRequest* aRequest); 600 601 void RunScriptWhenSafe(ScriptLoadRequest* aRequest); 602 603 Document* mDocument; // [WEAK] 604 nsCOMArray<nsIScriptLoaderObserver> mObservers; 605 ScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests; 606 // mLoadingAsyncRequests holds async requests while they're loading; when they 607 // have been loaded they are moved to mLoadedAsyncRequests. 608 ScriptLoadRequestList mLoadingAsyncRequests; 609 ScriptLoadRequestList mLoadedAsyncRequests; 610 ScriptLoadRequestList mDeferRequests; 611 ScriptLoadRequestList mXSLTRequests; 612 ScriptLoadRequestList mDynamicImportRequests; 613 RefPtr<ScriptLoadRequest> mParserBlockingRequest; 614 615 // List of script load request that are holding a buffer which has to be saved 616 // on the cache. 617 ScriptLoadRequestList mBytecodeEncodingQueue; 618 619 // In mRequests, the additional information here is stored by the element. 620 struct PreloadInfo { 621 RefPtr<ScriptLoadRequest> mRequest; 622 nsString mCharset; 623 }; 624 625 friend void ImplCycleCollectionUnlink(ScriptLoader::PreloadInfo& aField); 626 friend void ImplCycleCollectionTraverse( 627 nsCycleCollectionTraversalCallback& aCallback, 628 ScriptLoader::PreloadInfo& aField, const char* aName, uint32_t aFlags); 629 630 struct PreloadRequestComparator { EqualsPreloadRequestComparator631 bool Equals(const PreloadInfo& aPi, 632 ScriptLoadRequest* const& aRequest) const { 633 return aRequest == aPi.mRequest; 634 } 635 }; 636 637 struct PreloadURIComparator { 638 bool Equals(const PreloadInfo& aPi, nsIURI* const& aURI) const; 639 }; 640 641 nsTArray<PreloadInfo> mPreloads; 642 643 nsCOMPtr<nsIScriptElement> mCurrentScript; 644 nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript; 645 nsTArray<RefPtr<ScriptLoader>> mPendingChildLoaders; 646 uint32_t mParserBlockingBlockerCount; 647 uint32_t mBlockerCount; 648 uint32_t mNumberOfProcessors; 649 bool mEnabled; 650 bool mDeferEnabled; 651 bool mDeferCheckpointReached; 652 bool mBlockingDOMContentLoaded; 653 bool mLoadEventFired; 654 bool mGiveUpEncoding; 655 656 // Module map 657 nsRefPtrHashtable<nsURIHashKey, mozilla::GenericNonExclusivePromise::Private> 658 mFetchingModules; 659 nsRefPtrHashtable<nsURIHashKey, ModuleScript> mFetchedModules; 660 661 nsCOMPtr<nsIConsoleReportCollector> mReporter; 662 663 // Logging 664 public: 665 static LazyLogModule gCspPRLog; 666 static LazyLogModule gScriptLoaderLog; 667 }; 668 669 class nsAutoScriptLoaderDisabler { 670 public: nsAutoScriptLoaderDisabler(Document * aDoc)671 explicit nsAutoScriptLoaderDisabler(Document* aDoc) { 672 mLoader = aDoc->ScriptLoader(); 673 mWasEnabled = mLoader->GetEnabled(); 674 if (mWasEnabled) { 675 mLoader->SetEnabled(false); 676 } 677 } 678 ~nsAutoScriptLoaderDisabler()679 ~nsAutoScriptLoaderDisabler() { 680 if (mWasEnabled) { 681 mLoader->SetEnabled(true); 682 } 683 } 684 685 bool mWasEnabled; 686 RefPtr<ScriptLoader> mLoader; 687 }; 688 689 } // namespace dom 690 } // namespace mozilla 691 692 #endif // mozilla_dom_ScriptLoader_h 693