ported from UXP: Issue #1691 - Part 6b: Initial browser support for dynamic import from module scripts. M1342012 Factor out script fetch options from script load request classes. M1480720 Remove support for version parameter from script loader. M1428745 (86e0057e)

This commit is contained in:
2023-04-30 23:16:24 +08:00
parent 77a0f0ffcd
commit abf9ba5235
7 changed files with 558 additions and 200 deletions
+88 -44
View File
@@ -5,6 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ModuleLoadRequest.h" #include "ModuleLoadRequest.h"
#include "mozilla/HoldDropJSObjects.h"
#include "ModuleScript.h" #include "ModuleScript.h"
#include "ScriptLoader.h" #include "ScriptLoader.h"
@@ -14,58 +17,93 @@ namespace dom {
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest)
NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest) NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest, NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleLoadRequest)
mBaseURL,
mLoader,
mModuleScript,
mImports)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleLoadRequest,
ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL, mLoader, mModuleScript, mImports)
tmp->ClearDynamicImport();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleLoadRequest,
ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBaseURL, mLoader, mModuleScript, mImports)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleLoadRequest,
ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicReferencingPrivate)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicSpecifier)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicPromise)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest) NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest) NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI, static VisitedURLSet* NewVisitedSetForTopLevelImport(nsIURI* aURI) {
nsIScriptElement* aElement, auto set = new VisitedURLSet();
uint32_t aVersion, set->PutEntry(aURI);
CORSMode aCORSMode, return set;
const SRIMetadata &aIntegrity,
nsIURI* aReferrer,
mozilla::net::ReferrerPolicy aReferrerPolicy,
ScriptLoader* aLoader)
: ScriptLoadRequest(ScriptKind::Module,
aURI,
aElement,
aVersion,
aCORSMode,
aIntegrity,
aReferrer,
aReferrerPolicy),
mIsTopLevel(true),
mLoader(aLoader),
mVisitedSet(new VisitedURLSet())
{
mVisitedSet->PutEntry(aURI);
} }
ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI, /* static */ ModuleLoadRequest* ModuleLoadRequest::CreateTopLevel(
ModuleLoadRequest* aParent) nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
: ScriptLoadRequest(ScriptKind::Module, const SRIMetadata& aIntegrity, nsIURI* aReferrer, ScriptLoader* aLoader) {
aURI, return new ModuleLoadRequest(aURI, aFetchOptions, aIntegrity, aReferrer,
aParent->mElement, true, /* is top level */
aParent->mJSVersion, false, /* is dynamic import */
aParent->mCORSMode, aLoader, NewVisitedSetForTopLevelImport(aURI));
SRIMetadata(),
aParent->mURI,
aParent->mReferrerPolicy),
mIsTopLevel(false),
mLoader(aParent->mLoader),
mVisitedSet(aParent->mVisitedSet)
{
MOZ_ASSERT(mVisitedSet->Contains(aURI));
mIsInline = false;
mScriptMode = aParent->mScriptMode;
} }
/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateStaticImport(
nsIURI* aURI, ModuleLoadRequest* aParent) {
auto request =
new ModuleLoadRequest(aURI, aParent->mFetchOptions, SRIMetadata(),
aParent->mURI, false, /* is top level */
false, /* is dynamic import */
aParent->mLoader, aParent->mVisitedSet);
request->mIsInline = false;
request->mScriptMode = aParent->mScriptMode;
return request;
}
/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateDynamicImport(
nsIURI* aURI, ModuleScript* aScript,
JS::Handle<JS::Value> aReferencingPrivate, JS::Handle<JSString*> aSpecifier,
JS::Handle<JSObject*> aPromise) {
MOZ_ASSERT(aSpecifier);
MOZ_ASSERT(aPromise);
auto request = new ModuleLoadRequest(
aURI, aScript->FetchOptions(), SRIMetadata(), aScript->BaseURL(),
true, /* is top level */
true, /* is dynamic import */
aScript->Loader(), NewVisitedSetForTopLevelImport(aURI));
request->mIsInline = false;
request->mScriptMode = ScriptMode::eAsync;
request->mDynamicReferencingPrivate = aReferencingPrivate;
request->mDynamicSpecifier = aSpecifier;
request->mDynamicPromise = aPromise;
HoldJSObjects(request);
return request;
}
ModuleLoadRequest::ModuleLoadRequest(
nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
const SRIMetadata& aIntegrity, nsIURI* aReferrer, bool aIsTopLevel,
bool aIsDynamicImport, ScriptLoader* aLoader, VisitedURLSet* aVisitedSet)
: ScriptLoadRequest(ScriptKind::Module, aURI, aFetchOptions, aIntegrity,
aReferrer),
mIsTopLevel(aIsTopLevel),
mIsDynamicImport(aIsDynamicImport),
mLoader(aLoader),
mVisitedSet(aVisitedSet) {}
void ModuleLoadRequest::Cancel() void ModuleLoadRequest::Cancel()
{ {
ScriptLoadRequest::Cancel(); ScriptLoadRequest::Cancel();
@@ -167,5 +205,11 @@ ModuleLoadRequest::LoadFinished()
mLoader = nullptr; mLoader = nullptr;
} }
void ModuleLoadRequest::ClearDynamicImport() {
mDynamicReferencingPrivate = JS::UndefinedValue();
mDynamicSpecifier = nullptr;
mDynamicPromise = nullptr;
}
} // dom namespace } // dom namespace
} // mozilla namespace } // mozilla namespace
+32 -12
View File
@@ -38,30 +38,42 @@ class ModuleLoadRequest final : public ScriptLoadRequest
ModuleLoadRequest(const ModuleLoadRequest& aOther) = delete; ModuleLoadRequest(const ModuleLoadRequest& aOther) = delete;
ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete; ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete;
ModuleLoadRequest(nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
const SRIMetadata& aIntegrity, nsIURI* aReferrer,
bool aIsTopLevel, bool aIsDynamicImport,
ScriptLoader* aLoader, VisitedURLSet* aVisitedSet);
public: public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleLoadRequest,
ScriptLoadRequest)
// Create a top-level module load request. // Create a top-level module load request.
ModuleLoadRequest(nsIURI* aURI, static ModuleLoadRequest* CreateTopLevel(nsIURI* aURI,
nsIScriptElement* aElement, ScriptFetchOptions* aFetchOptions,
uint32_t aVersion, const SRIMetadata& aIntegrity,
CORSMode aCORSMode, nsIURI* aReferrer,
const SRIMetadata& aIntegrity, ScriptLoader* aLoader);
nsIURI* aReferrer,
mozilla::net::ReferrerPolicy,
ScriptLoader* aLoader);
// Create a module load request for an imported module. // Create a module load request for a static module import.
ModuleLoadRequest(nsIURI* aURI, static ModuleLoadRequest* CreateStaticImport(nsIURI* aURI,
ModuleLoadRequest* aParent); ModuleLoadRequest* aParent);
// Create a module load request for dynamic module import.
static ModuleLoadRequest* CreateDynamicImport(
nsIURI* aURI, ModuleScript* aScript,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSString*> aSpecifier, JS::Handle<JSObject*> aPromise);
bool IsTopLevel() const override { bool IsTopLevel() const override {
return mIsTopLevel; return mIsTopLevel;
} }
bool IsDynamicImport() const { return mIsDynamicImport; }
void SetReady() override; void SetReady() override;
void Cancel() override; void Cancel() override;
void ClearDynamicImport();
void ModuleLoaded(); void ModuleLoaded();
void ModuleErrored(); void ModuleErrored();
@@ -75,6 +87,9 @@ private:
public: public:
// Is this a request for a top level module script or an import? // Is this a request for a top level module script or an import?
const bool mIsTopLevel; const bool mIsTopLevel;
// Is this the top level request for a dynamic module import?
const bool mIsDynamicImport;
// The base URL used for resolving relative module imports. // The base URL used for resolving relative module imports.
nsCOMPtr<nsIURI> mBaseURL; nsCOMPtr<nsIURI> mBaseURL;
@@ -98,6 +113,11 @@ public:
// Set of module URLs visited while fetching the module graph this request is // Set of module URLs visited while fetching the module graph this request is
// part of. // part of.
RefPtr<VisitedURLSet> mVisitedSet; RefPtr<VisitedURLSet> mVisitedSet;
// For dynamic imports, the details to pass to FinishDynamicImport.
JS::Heap<JS::Value> mDynamicReferencingPrivate;
JS::Heap<JSString*> mDynamicSpecifier;
JS::Heap<JSObject*> mDynamicPromise;
}; };
} // dom namespace } // dom namespace
+31 -9
View File
@@ -8,9 +8,11 @@
* A class that handles loading and evaluation of <script> elements. * A class that handles loading and evaluation of <script> elements.
*/ */
#include "ScriptLoader.h"
#include "ModuleScript.h" #include "ModuleScript.h"
#include "mozilla/HoldDropJSObjects.h" #include "mozilla/HoldDropJSObjects.h"
#include "ScriptLoader.h"
#include "jsfriendapi.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@@ -24,6 +26,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader) NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL) NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
tmp->UnlinkModuleRecord(); tmp->UnlinkModuleRecord();
tmp->mParseError.setUndefined(); tmp->mParseError.setUndefined();
@@ -32,6 +35,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
@@ -43,11 +47,13 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript) NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript) NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL) ModuleScript::ModuleScript(ScriptLoader* aLoader,
: mLoader(aLoader), ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL)
mBaseURL(aBaseURL) : mLoader(aLoader),
{ mFetchOptions(aFetchOptions),
mBaseURL(aBaseURL) {
MOZ_ASSERT(mLoader); MOZ_ASSERT(mLoader);
MOZ_ASSERT(mFetchOptions);
MOZ_ASSERT(mBaseURL); MOZ_ASSERT(mBaseURL);
MOZ_ASSERT(!mModuleRecord); MOZ_ASSERT(!mModuleRecord);
MOZ_ASSERT(!HasParseError()); MOZ_ASSERT(!HasParseError());
@@ -57,7 +63,9 @@ ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL)
void void
ModuleScript::UnlinkModuleRecord() ModuleScript::UnlinkModuleRecord()
{ {
// Remove module's back reference to this object request if present. // Remove the module record's pointer to this object if present and
// decrement our reference count. The reference is added by
// SetModuleRecord() below.
if (mModuleRecord) { if (mModuleRecord) {
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).toPrivate() == MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).toPrivate() ==
this); this);
@@ -82,8 +90,9 @@ ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
mModuleRecord = aModuleRecord; mModuleRecord = aModuleRecord;
// Make module's host defined field point to this module script object. // Make module's host defined field point to this object and
// This is cleared in the UnlinkModuleRecord(). // increment our reference count. This is decremented by
// UnlinkModuleRecord() above.
JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this)); JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
HoldJSObjects(this); HoldJSObjects(this);
} }
@@ -98,13 +107,26 @@ ModuleScript::SetParseError(const JS::Value& aError)
UnlinkModuleRecord(); UnlinkModuleRecord();
mParseError = aError; mParseError = aError;
HoldJSObjects(this); HoldJSObjects(this);
AddRef();
}
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate) {
auto script = static_cast<ModuleScript*>(aPrivate.toPrivate());
if (script) {
MOZ_ASSERT(JS::GetModulePrivate(script->mModuleRecord.unbarrieredGet()) ==
aPrivate);
script->UnlinkModuleRecord();
}
} }
void void
ModuleScript::SetErrorToRethrow(const JS::Value& aError) ModuleScript::SetErrorToRethrow(const JS::Value& aError)
{ {
MOZ_ASSERT(!aError.isUndefined()); MOZ_ASSERT(!aError.isUndefined());
MOZ_ASSERT(!HasErrorToRethrow());
// This is only called after SetModuleRecord() or SetParseError() so we don't
// need to call HoldJSObjects() here.
MOZ_ASSERT(mModuleRecord || HasParseError());
mErrorToRethrow = aError; mErrorToRethrow = aError;
} }
+7 -1
View File
@@ -18,9 +18,12 @@ namespace dom {
class ScriptLoader; class ScriptLoader;
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate);
class ModuleScript final : public nsISupports class ModuleScript final : public nsISupports
{ {
RefPtr<ScriptLoader> mLoader; RefPtr<ScriptLoader> mLoader;
RefPtr<ScriptFetchOptions> mFetchOptions;
nsCOMPtr<nsIURI> mBaseURL; nsCOMPtr<nsIURI> mBaseURL;
JS::Heap<JSObject*> mModuleRecord; JS::Heap<JSObject*> mModuleRecord;
JS::Heap<JS::Value> mParseError; JS::Heap<JS::Value> mParseError;
@@ -32,7 +35,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
ModuleScript(ScriptLoader* aLoader, ModuleScript(ScriptLoader* aLoader, ScriptFetchOptions* aFetchOptions,
nsIURI* aBaseURL); nsIURI* aBaseURL);
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord); void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
@@ -40,6 +43,7 @@ public:
void SetErrorToRethrow(const JS::Value& aError); void SetErrorToRethrow(const JS::Value& aError);
ScriptLoader* Loader() const { return mLoader; } ScriptLoader* Loader() const { return mLoader; }
ScriptFetchOptions* FetchOptions() const { return mFetchOptions; }
JSObject* ModuleRecord() const { return mModuleRecord; } JSObject* ModuleRecord() const { return mModuleRecord; }
nsIURI* BaseURL() const { return mBaseURL; } nsIURI* BaseURL() const { return mBaseURL; }
@@ -49,6 +53,8 @@ public:
bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); } bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
void UnlinkModuleRecord(); void UnlinkModuleRecord();
friend void HostFinalizeTopLevelScript(JSFreeOp*, const JS::Value&);
}; };
} // dom namespace } // dom namespace
+1 -1
View File
@@ -155,7 +155,7 @@ ScriptLoadHandler::EnsureDecoder(nsIIncrementalStreamLoader *aLoader,
// request. // request.
nsAutoString hintCharset; nsAutoString hintCharset;
if (!mRequest->IsPreload()) { if (!mRequest->IsPreload()) {
mRequest->mElement->GetScriptCharset(hintCharset); mRequest->Element()->GetScriptCharset(hintCharset);
} else { } else {
nsTArray<ScriptLoader::PreloadInfo>::index_type i = nsTArray<ScriptLoader::PreloadInfo>::index_type i =
mScriptLoader->mPreloads.IndexOf(mRequest, 0, mScriptLoader->mPreloads.IndexOf(mRequest, 0,
+317 -112
View File
@@ -74,6 +74,31 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
const char* aName, const char* aName,
uint32_t aFlags = 0); uint32_t aFlags = 0);
//////////////////////////////////////////////////////////////
// ScriptFetchOptions
//////////////////////////////////////////////////////////////
NS_IMPL_CYCLE_COLLECTION(ScriptFetchOptions,
mElement,
mTriggeringPrincipal)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ScriptFetchOptions, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ScriptFetchOptions, Release)
ScriptFetchOptions::ScriptFetchOptions(mozilla::CORSMode aCORSMode,
mozilla::net::ReferrerPolicy aReferrerPolicy,
nsIScriptElement* aElement,
nsIPrincipal* aTriggeringPrincipal)
: mCORSMode(aCORSMode)
, mReferrerPolicy(aReferrerPolicy)
, mElement(aElement)
, mTriggeringPrincipal(aTriggeringPrincipal)
{
}
ScriptFetchOptions::~ScriptFetchOptions()
{}
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
// ScriptLoadRequest // ScriptLoadRequest
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
@@ -87,11 +112,12 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest) NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadRequest) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions)
tmp->mScript = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadRequest) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
ScriptLoadRequest::~ScriptLoadRequest() ScriptLoadRequest::~ScriptLoadRequest()
@@ -104,6 +130,8 @@ ScriptLoadRequest::~ScriptLoadRequest()
// But play it safe in release builds and try to clean them up here // But play it safe in release builds and try to clean them up here
// as a fail safe. // as a fail safe.
MaybeCancelOffThreadScript(); MaybeCancelOffThreadScript();
DropJSObjects(this);
} }
void void
@@ -153,6 +181,12 @@ ScriptLoadRequest::SetScriptMode(bool aDeferAttr, bool aAsyncAttr)
} }
} }
void ScriptLoadRequest::SetScript(JSScript* aScript) {
MOZ_ASSERT(!mScript);
mScript = aScript;
HoldJSObjects(this);
}
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
// ScriptLoadRequestList // ScriptLoadRequestList
@@ -239,11 +273,12 @@ NS_IMPL_CYCLE_COLLECTION(ScriptLoader,
mNonAsyncExternalScriptInsertedRequests, mNonAsyncExternalScriptInsertedRequests,
mLoadingAsyncRequests, mLoadingAsyncRequests,
mLoadedAsyncRequests, mLoadedAsyncRequests,
mDeferRequests, mDeferRequests,
mXSLTRequests, mXSLTRequests,
mParserBlockingRequest, mDynamicImportRequests,
mPreloads, mParserBlockingRequest,
mPendingChildLoaders, mPreloads,
mPendingChildLoaders,
mFetchedModules) mFetchedModules)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoader) NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoader)
@@ -260,6 +295,7 @@ ScriptLoader::ScriptLoader(nsIDocument *aDocument)
mBlockingDOMContentLoaded(false), mBlockingDOMContentLoaded(false),
mReporter(new ConsoleReportCollector()) mReporter(new ConsoleReportCollector())
{ {
EnsureModuleHooksInitialized();
} }
ScriptLoader::~ScriptLoader() ScriptLoader::~ScriptLoader()
@@ -290,6 +326,11 @@ ScriptLoader::~ScriptLoader()
req->FireScriptAvailable(NS_ERROR_ABORT); req->FireScriptAvailable(NS_ERROR_ABORT);
} }
for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req;
req = req->getNext()) {
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
}
for(ScriptLoadRequest* req = mNonAsyncExternalScriptInsertedRequests.getFirst(); for(ScriptLoadRequest* req = mNonAsyncExternalScriptInsertedRequests.getFirst();
req; req;
req = req->getNext()) { req = req->getNext()) {
@@ -543,7 +584,7 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
nsCOMPtr<nsIDocument> master = mDocument->MasterDocument(); nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
if (master != mDocument) { if (master != mDocument) {
masterScriptUpdater.emplace(master->ScriptLoader(), masterScriptUpdater.emplace(master->ScriptLoader(),
aRequest->mElement); aRequest->Element());
} }
JSContext* cx = aes.cx(); JSContext* cx = aes.cx();
@@ -568,7 +609,8 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr)); MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL); RefPtr<ModuleScript> moduleScript =
new ModuleScript(this, aRequest->mFetchOptions, aRequest->mBaseURL);
aRequest->mModuleScript = moduleScript; aRequest->mModuleScript = moduleScript;
if (!module) { if (!module) {
@@ -782,7 +824,8 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent,
{ {
MOZ_ASSERT(aURI); MOZ_ASSERT(aURI);
RefPtr<ModuleLoadRequest> childRequest = new ModuleLoadRequest(aURI, aParent); RefPtr<ModuleLoadRequest> childRequest =
ModuleLoadRequest::CreateStaticImport(aURI, aParent);
aParent->mImports.AppendElement(childRequest); aParent->mImports.AppendElement(childRequest);
@@ -805,6 +848,12 @@ HostResolveImportedModule(JSContext* aCx,
JS::Handle<JSString*> aSpecifier) JS::Handle<JSString*> aSpecifier)
{ {
// Let referencing module script be referencingModule.[[HostDefined]]. // Let referencing module script be referencingModule.[[HostDefined]].
if (aReferencingPrivate.isUndefined()) {
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
JSMSG_IMPORT_SCRIPT_NOT_FOUND);
return nullptr;
}
auto script = static_cast<ModuleScript*>(aReferencingPrivate.toPrivate()); auto script = static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) == aReferencingPrivate); MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) == aReferencingPrivate);
@@ -869,16 +918,108 @@ HostPopulateImportMeta(JSContext* aCx, JS::Handle<JSObject*> aModule,
return JS_DefineProperty(aCx, aMetaObject, "url", urlString, JSPROP_ENUMERATE); return JS_DefineProperty(aCx, aMetaObject, "url", urlString, JSPROP_ENUMERATE);
} }
static void bool HostImportModuleDynamically(JSContext* aCx,
EnsureModuleResolveHook(JSContext* aCx) JS::Handle<JS::Value> aReferencingPrivate,
{ JS::Handle<JSString*> aSpecifier,
JSRuntime* rt = JS_GetRuntime(aCx); JS::Handle<JSObject*> aPromise) {
if (aReferencingPrivate.isUndefined()) {
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
JSMSG_IMPORT_SCRIPT_NOT_FOUND);
return false;
}
auto script = static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) ==
aReferencingPrivate);
// Attempt to resolve the module specifier.
nsAutoJSString string;
if (!string.init(aCx, aSpecifier)) {
return false;
}
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
if (!uri) {
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
JSMSG_BAD_MODULE_SPECIFIER, string.get());
return false;
}
// Create a new top-level load request.
RefPtr<ModuleLoadRequest> request = ModuleLoadRequest::CreateDynamicImport(
uri, script, aReferencingPrivate, aSpecifier, aPromise);
script->Loader()->StartDynamicImport(request);
return true;
}
void ScriptLoader::StartDynamicImport(ModuleLoadRequest* aRequest) {
mDynamicImportRequests.AppendElement(aRequest);
nsresult rv = StartLoad(aRequest, NS_LITERAL_STRING("script"), false);
if (NS_FAILED(rv)) {
FinishDynamicImport(aRequest, rv);
}
}
void ScriptLoader::FinishDynamicImport(ModuleLoadRequest* aRequest,
nsresult aResult) {
AutoJSAPI jsapi;
MOZ_ALWAYS_TRUE(jsapi.Init(aRequest->mDynamicPromise));
FinishDynamicImport(jsapi.cx(), aRequest, aResult);
}
void ScriptLoader::FinishDynamicImport(JSContext* aCx,
ModuleLoadRequest* aRequest,
nsresult aResult) {
// Complete the dynamic import, report failures indicated by aResult or as a
// pending exception on the context.
if (NS_FAILED(aResult)) {
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
JSMSG_IMPORT_SCRIPT_NOT_FOUND);
}
JS::Rooted<JS::Value> referencingScript(aCx,
aRequest->mDynamicReferencingPrivate);
JS::Rooted<JSString*> specifier(aCx, aRequest->mDynamicSpecifier);
JS::Rooted<JSObject*> promise(aCx, aRequest->mDynamicPromise);
JS::FinishDynamicModuleImport(aCx, referencingScript, specifier, promise);
// FinishDynamicModuleImport clears any pending exception.
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
aRequest->ClearDynamicImport();
}
static void DynamicImportPrefChangedCallback(const char* aPrefName,
void* aClosure) {
bool enabled = Preferences::GetBool(aPrefName);
JS::ModuleDynamicImportHook hook =
enabled ? HostImportModuleDynamically : nullptr;
AutoJSAPI jsapi;
jsapi.Init();
JS::SetModuleDynamicImportHook(jsapi.cx(), hook);
}
void ScriptLoader::EnsureModuleHooksInitialized() {
AutoJSAPI jsapi;
jsapi.Init();
JSRuntime* rt = JS_GetRuntime(jsapi.cx());
if (JS::GetModuleResolveHook(rt)) { if (JS::GetModuleResolveHook(rt)) {
return; return;
} }
JS::SetModuleResolveHook(rt, HostResolveImportedModule); JS::SetModuleResolveHook(rt, HostResolveImportedModule);
JS::SetModuleMetadataHook(aCx, HostPopulateImportMeta); JS::SetModuleMetadataHook(jsapi.cx(), HostPopulateImportMeta);
JS::SetScriptPrivateFinalizeHook(jsapi.cx(), HostFinalizeTopLevelScript);
Preferences::RegisterCallbackAndCall(DynamicImportPrefChangedCallback,
"javascript.options.dynamicImport",
(void*)nullptr);
} }
void void
@@ -910,12 +1051,22 @@ public:
: mLoader(aLoader) : mLoader(aLoader)
, mRequest(aRequest) , mRequest(aRequest)
{} {}
NS_IMETHOD Run() override NS_IMETHOD Run() override {
{ if (mRequest->IsModuleRequest() &&
mRequest->AsModuleRequest()->IsDynamicImport()) {
mLoader->ProcessDynamicImport(mRequest->AsModuleRequest());
return NS_OK;
}
return mLoader->ProcessRequest(mRequest); return mLoader->ProcessRequest(mRequest);
} }
}; };
void ScriptLoader::RunScriptWhenSafe(ScriptLoadRequest* aRequest) {
auto runnable = new ScriptRequestProcessor(this, aRequest);
nsContentUtils::AddScriptRunner(runnable);
}
void void
ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest) ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
{ {
@@ -927,12 +1078,13 @@ ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
} }
} }
if (aRequest->mIsInline && if (aRequest->IsDynamicImport()) {
aRequest->mElement->GetParserCreated() == NOT_FROM_PARSER) MOZ_ASSERT(aRequest->isInList());
{ RefPtr<ScriptLoadRequest> req = mDynamicImportRequests.Steal(aRequest);
MOZ_ASSERT(!aRequest->isInList()); RunScriptWhenSafe(req);
nsContentUtils::AddScriptRunner( } else if (aRequest->mIsInline &&
new ScriptRequestProcessor(this, aRequest)); aRequest->Element()->GetParserCreated() == NOT_FROM_PARSER) {
RunScriptWhenSafe(aRequest);
} else { } else {
MaybeMoveToLoadedList(aRequest); MaybeMoveToLoadedList(aRequest);
ProcessPendingRequests(); ProcessPendingRequests();
@@ -992,8 +1144,6 @@ ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
return false; return false;
} }
EnsureModuleResolveHook(jsapi.cx());
JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord()); JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord());
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module)); bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module));
@@ -1039,8 +1189,8 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
? nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD ? nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD
: nsIContentPolicy::TYPE_INTERNAL_SCRIPT; : nsIContentPolicy::TYPE_INTERNAL_SCRIPT;
nsCOMPtr<nsINode> context; nsCOMPtr<nsINode> context;
if (aRequest->mElement) { if (aRequest->Element()) {
context = do_QueryInterface(aRequest->mElement); context = do_QueryInterface(aRequest->Element());
} }
else { else {
context = mDocument; context = mDocument;
@@ -1057,21 +1207,21 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
// According to the spec, module scripts have different behaviour to classic // According to the spec, module scripts have different behaviour to classic
// scripts and always use CORS. // scripts and always use CORS.
securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
if (aRequest->mCORSMode == CORS_NONE) { if (aRequest->CORSMode() == CORS_NONE) {
securityFlags |= nsILoadInfo::SEC_COOKIES_OMIT; securityFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
} else if (aRequest->mCORSMode == CORS_ANONYMOUS) { } else if (aRequest->CORSMode() == CORS_ANONYMOUS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN; securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
} else { } else {
MOZ_ASSERT(aRequest->mCORSMode == CORS_USE_CREDENTIALS); MOZ_ASSERT(aRequest->CORSMode() == CORS_USE_CREDENTIALS);
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE; securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
} }
} else { } else {
securityFlags = aRequest->mCORSMode == CORS_NONE securityFlags = aRequest->CORSMode() == CORS_NONE
? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL
: nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
if (aRequest->mCORSMode == CORS_ANONYMOUS) { if (aRequest->CORSMode() == CORS_ANONYMOUS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN; securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
} else if (aRequest->mCORSMode == CORS_USE_CREDENTIALS) { } else if (aRequest->CORSMode() == CORS_USE_CREDENTIALS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE; securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
} }
} }
@@ -1110,7 +1260,7 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
NS_LITERAL_CSTRING("*/*"), NS_LITERAL_CSTRING("*/*"),
false); false);
httpChannel->SetReferrerWithPolicy(aRequest->mReferrer, httpChannel->SetReferrerWithPolicy(aRequest->mReferrer,
aRequest->mReferrerPolicy); aRequest->ReferrerPolicy());
nsCOMPtr<nsIHttpChannelInternal> internalChannel(do_QueryInterface(httpChannel)); nsCOMPtr<nsIHttpChannelInternal> internalChannel(do_QueryInterface(httpChannel));
if (internalChannel) { if (internalChannel) {
@@ -1232,22 +1382,21 @@ ScriptLoadRequest*
ScriptLoader::CreateLoadRequest(ScriptKind aKind, ScriptLoader::CreateLoadRequest(ScriptKind aKind,
nsIURI* aURI, nsIURI* aURI,
nsIScriptElement* aElement, nsIScriptElement* aElement,
uint32_t aVersion, CORSMode aCORSMode, nsIPrincipal* aTriggeringPrincipal,
CORSMode aCORSMode,
const SRIMetadata& aIntegrity, const SRIMetadata& aIntegrity,
mozilla::net::ReferrerPolicy aReferrerPolicy) mozilla::net::ReferrerPolicy aReferrerPolicy)
{ {
nsIURI* referrer = mDocument->GetDocumentURI(); nsIURI* referrer = mDocument->GetDocumentURI();
ScriptFetchOptions* fetchOptions =
new ScriptFetchOptions(aCORSMode, aReferrerPolicy, aElement, aTriggeringPrincipal);
if (aKind == ScriptKind::Classic) { if (aKind == ScriptKind::Classic) {
return new ScriptLoadRequest(aKind, aURI, aElement, return new ScriptLoadRequest(aKind, aURI, fetchOptions, aIntegrity, referrer);
aVersion, aCORSMode,
aIntegrity,
referrer, aReferrerPolicy);
} }
MOZ_ASSERT(aKind == ScriptKind::Module); MOZ_ASSERT(aKind == ScriptKind::Module);
return new ModuleLoadRequest(aURI, aElement, aVersion, aCORSMode, return ModuleLoadRequest::CreateTopLevel(aURI, fetchOptions, aIntegrity, referrer, this);
aIntegrity, referrer, aReferrerPolicy, this);
} }
bool bool
@@ -1334,7 +1483,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
// preloaded // preloaded
// note that a script-inserted script can steal a preload! // note that a script-inserted script can steal a preload!
request = mPreloads[i].mRequest; request = mPreloads[i].mRequest;
request->mElement = aElement; request->SetElement(aElement);
nsString preloadCharset(mPreloads[i].mCharset); nsString preloadCharset(mPreloads[i].mCharset);
mPreloads.RemoveElementAt(i); mPreloads.RemoveElementAt(i);
@@ -1343,8 +1492,8 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
nsAutoString elementCharset; nsAutoString elementCharset;
aElement->GetScriptCharset(elementCharset); aElement->GetScriptCharset(elementCharset);
if (elementCharset.Equals(preloadCharset) && if (elementCharset.Equals(preloadCharset) &&
ourCORSMode == request->mCORSMode && ourCORSMode == request->CORSMode() &&
ourRefPolicy == request->mReferrerPolicy && ourRefPolicy == request->ReferrerPolicy() &&
scriptKind == request->mKind) { scriptKind == request->mKind) {
rv = CheckContentPolicy(mDocument, aElement, request->mURI, type, false); rv = CheckContentPolicy(mDocument, aElement, request->mURI, type, false);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@@ -1387,9 +1536,10 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
} }
} }
request = CreateLoadRequest(scriptKind, scriptURI, aElement, nsCOMPtr<nsIPrincipal> principal = scriptContent->NodePrincipal();
version, ourCORSMode, sriMetadata,
ourRefPolicy); request = CreateLoadRequest(scriptKind, scriptURI, aElement, principal,
ourCORSMode, sriMetadata, ourRefPolicy);
request->mIsInline = false; request->mIsInline = false;
request->SetScriptMode(aElement->GetScriptDeferred(), request->SetScriptMode(aElement->GetScriptDeferred(),
aElement->GetScriptAsync()); aElement->GetScriptAsync());
@@ -1410,8 +1560,6 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
NS_ASSERTION(!request->InCompilingStage() || request->IsModuleRequest(), NS_ASSERTION(!request->InCompilingStage() || request->IsModuleRequest(),
"Request should not yet be in compiling stage."); "Request should not yet be in compiling stage.");
request->mJSVersion = version;
if (request->IsAsyncScript()) { if (request->IsAsyncScript()) {
AddAsyncRequest(request); AddAsyncRequest(request);
if (request->IsReadyToRun()) { if (request->IsReadyToRun()) {
@@ -1509,10 +1657,10 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
// Inline scripts ignore their CORS mode and are always CORS_NONE. // Inline scripts ignore their CORS mode and are always CORS_NONE.
request = CreateLoadRequest(scriptKind, mDocument->GetDocumentURI(), aElement, request = CreateLoadRequest(scriptKind, mDocument->GetDocumentURI(), aElement,
version, CORS_NONE, mDocument->NodePrincipal(),
CORS_NONE,
SRIMetadata(), // SRI doesn't apply SRIMetadata(), // SRI doesn't apply
ourRefPolicy); ourRefPolicy);
request->mJSVersion = version;
request->mIsInline = true; request->mIsInline = true;
request->mLineNo = aElement->GetScriptLineNumber(); request->mLineNo = aElement->GetScriptLineNumber();
@@ -1774,7 +1922,7 @@ ScriptLoader::GetScriptSource(ScriptLoadRequest* aRequest, nsAutoString& inlineD
if (aRequest->mIsInline) { if (aRequest->mIsInline) {
// XXX This is inefficient - GetText makes multiple // XXX This is inefficient - GetText makes multiple
// copies. // copies.
aRequest->mElement->GetScriptText(inlineData); aRequest->Element()->GetScriptText(inlineData);
return SourceBufferHolder(inlineData.get(), return SourceBufferHolder(inlineData.get(),
inlineData.Length(), inlineData.Length(),
SourceBufferHolder::NoOwnership); SourceBufferHolder::NoOwnership);
@@ -1795,15 +1943,22 @@ ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
NS_ENSURE_ARG(aRequest); NS_ENSURE_ARG(aRequest);
if (aRequest->IsModuleRequest() && if (aRequest->IsModuleRequest()) {
!aRequest->AsModuleRequest()->mModuleScript) ModuleLoadRequest* request = aRequest->AsModuleRequest();
{ if (request->mModuleScript) {
// There was an error fetching a module script. Nothing to do here. if (!InstantiateModuleTree(request)) {
FireScriptAvailable(NS_ERROR_FAILURE, aRequest); request->mModuleScript = nullptr;
return NS_OK; }
}
if (!request->mModuleScript) {
// There was an error fetching a module script. Nothing to do here.
FireScriptAvailable(NS_ERROR_FAILURE, aRequest);
return NS_OK;
}
} }
nsCOMPtr<nsINode> scriptElem = do_QueryInterface(aRequest->mElement); nsCOMPtr<nsINode> scriptElem = do_QueryInterface(aRequest->Element());
nsCOMPtr<nsIDocument> doc; nsCOMPtr<nsIDocument> doc;
if (!aRequest->mIsInline) { if (!aRequest->mIsInline) {
@@ -1811,13 +1966,13 @@ ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
} }
nsCOMPtr<nsIScriptElement> oldParserInsertedScript; nsCOMPtr<nsIScriptElement> oldParserInsertedScript;
uint32_t parserCreated = aRequest->mElement->GetParserCreated(); uint32_t parserCreated = aRequest->Element()->GetParserCreated();
if (parserCreated) { if (parserCreated) {
oldParserInsertedScript = mCurrentParserInsertedScript; oldParserInsertedScript = mCurrentParserInsertedScript;
mCurrentParserInsertedScript = aRequest->mElement; mCurrentParserInsertedScript = aRequest->Element();
} }
aRequest->mElement->BeginEvaluating(); aRequest->Element()->BeginEvaluating();
FireScriptAvailable(NS_OK, aRequest); FireScriptAvailable(NS_OK, aRequest);
@@ -1862,7 +2017,7 @@ ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
FireScriptEvaluated(rv, aRequest); FireScriptEvaluated(rv, aRequest);
aRequest->mElement->EndEvaluating(); aRequest->Element()->EndEvaluating();
if (parserCreated) { if (parserCreated) {
mCurrentParserInsertedScript = oldParserInsertedScript; mCurrentParserInsertedScript = oldParserInsertedScript;
@@ -1885,13 +2040,32 @@ ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
return rv; return rv;
} }
void ScriptLoader::ProcessDynamicImport(ModuleLoadRequest* aRequest) {
if (aRequest->mModuleScript) {
if (!InstantiateModuleTree(aRequest)) {
aRequest->mModuleScript = nullptr;
}
}
nsresult rv = NS_ERROR_FAILURE;
if (aRequest->mModuleScript) {
rv = EvaluateScript(aRequest);
}
if (NS_FAILED(rv)) {
FinishDynamicImport(aRequest, rv);
}
return;
}
void void
ScriptLoader::FireScriptAvailable(nsresult aResult, ScriptLoader::FireScriptAvailable(nsresult aResult,
ScriptLoadRequest* aRequest) ScriptLoadRequest* aRequest)
{ {
for (int32_t i = 0; i < mObservers.Count(); i++) { for (int32_t i = 0; i < mObservers.Count(); i++) {
nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i]; nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i];
obs->ScriptAvailable(aResult, aRequest->mElement, obs->ScriptAvailable(aResult, aRequest->Element(),
aRequest->mIsInline, aRequest->mURI, aRequest->mIsInline, aRequest->mURI,
aRequest->mLineNo); aRequest->mLineNo);
} }
@@ -1905,7 +2079,7 @@ ScriptLoader::FireScriptEvaluated(nsresult aResult,
{ {
for (int32_t i = 0; i < mObservers.Count(); i++) { for (int32_t i = 0; i < mObservers.Count(); i++) {
nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i]; nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i];
obs->ScriptEvaluated(aResult, aRequest->mElement, obs->ScriptEvaluated(aResult, aRequest->Element(),
aRequest->mIsInline); aRequest->mIsInline);
} }
@@ -1934,10 +2108,9 @@ ScriptLoader::GetScriptGlobalObject()
} }
nsresult nsresult
ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi, ScriptLoader::FillCompileOptionsForRequest(
ScriptLoadRequest* aRequest, const mozilla::dom::AutoJSAPI& jsapi, ScriptLoadRequest* aRequest,
JS::Handle<JSObject*> aScopeChain, JS::Handle<JSObject*> aScopeChain, JS::CompileOptions* aOptions)
JS::CompileOptions* aOptions)
{ {
// It's very important to use aRequest->mURI, not the final URI of the channel // It's very important to use aRequest->mURI, not the final URI of the channel
// aRequest ended up getting script data from, as the script filename. // aRequest ended up getting script data from, as the script filename.
@@ -1957,7 +2130,6 @@ ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi,
aOptions->setIntroductionType(isScriptElement ? "scriptElement" aOptions->setIntroductionType(isScriptElement ? "scriptElement"
: "importedModule"); : "importedModule");
aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo); aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
aOptions->setVersion(JSVersion(aRequest->mJSVersion));
aOptions->setIsRunOnce(true); aOptions->setIsRunOnce(true);
// We only need the setNoScriptRval bit when compiling off-thread here, since // We only need the setNoScriptRval bit when compiling off-thread here, since
// otherwise nsJSUtils::EvaluateString will set it up for us. // otherwise nsJSUtils::EvaluateString will set it up for us.
@@ -1975,8 +2147,8 @@ ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi,
// Only do this for classic scripts. // Only do this for classic scripts.
JSContext* cx = jsapi.cx(); JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> elementVal(cx); JS::Rooted<JS::Value> elementVal(cx);
MOZ_ASSERT(aRequest->mElement); MOZ_ASSERT(aRequest->Element());
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, aRequest->mElement, if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, aRequest->Element(),
&elementVal, &elementVal,
/* aAllowWrapping = */ true))) { /* aAllowWrapping = */ true))) {
MOZ_ASSERT(elementVal.isObject()); MOZ_ASSERT(elementVal.isObject());
@@ -1987,6 +2159,19 @@ ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi,
return NS_OK; return NS_OK;
} }
class MOZ_RAII AutoSetProcessingScriptTag {
nsCOMPtr<nsIScriptContext> mContext;
bool mOldTag;
public:
explicit AutoSetProcessingScriptTag(nsIScriptContext* aContext)
: mContext(aContext), mOldTag(mContext->GetProcessingScriptTag()) {
mContext->SetProcessingScriptTag(true);
}
~AutoSetProcessingScriptTag() { mContext->SetProcessingScriptTag(mOldTag); }
};
nsresult nsresult
ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
{ {
@@ -1995,7 +2180,7 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement)); nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->Element()));
nsIDocument* ownerDoc = scriptContent->OwnerDoc(); nsIDocument* ownerDoc = scriptContent->OwnerDoc();
if (ownerDoc != mDocument) { if (ownerDoc != mDocument) {
// Willful violation of HTML5 as of 2010-12-01 // Willful violation of HTML5 as of 2010-12-01
@@ -2018,11 +2203,6 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
JSVersion version = JSVersion(aRequest->mJSVersion);
if (version == JSVERSION_UNKNOWN) {
return NS_OK;
}
// New script entry point required, due to the "Create a script" sub-step of // New script entry point required, due to the "Create a script" sub-step of
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block // http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
nsAutoMicroTask mt; nsAutoMicroTask mt;
@@ -2030,8 +2210,7 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
JSContext* cx = aes.cx(); JSContext* cx = aes.cx();
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject()); JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
bool oldProcessingScriptTag = context->GetProcessingScriptTag(); AutoSetProcessingScriptTag setProcessingScriptTag(context);
context->SetProcessingScriptTag(true);
nsresult rv; nsresult rv;
{ {
Maybe<AutoCurrentScriptUpdater> masterScriptUpdater; Maybe<AutoCurrentScriptUpdater> masterScriptUpdater;
@@ -2043,15 +2222,13 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
// script. So let's update the mCurrentScript of the ScriptLoader // script. So let's update the mCurrentScript of the ScriptLoader
// of the master document too. // of the master document too.
masterScriptUpdater.emplace(master->ScriptLoader(), masterScriptUpdater.emplace(master->ScriptLoader(),
aRequest->mElement); aRequest->Element());
} }
if (aRequest->IsModuleRequest()) { if (aRequest->IsModuleRequest()) {
// For modules, currentScript is set to null. // For modules, currentScript is set to null.
AutoCurrentScriptUpdater scriptUpdater(this, nullptr); AutoCurrentScriptUpdater scriptUpdater(this, nullptr);
EnsureModuleResolveHook(cx);
ModuleLoadRequest* request = aRequest->AsModuleRequest(); ModuleLoadRequest* request = aRequest->AsModuleRequest();
MOZ_ASSERT(request->mModuleScript); MOZ_ASSERT(request->mModuleScript);
MOZ_ASSERT(!request->mOffThreadToken); MOZ_ASSERT(!request->mOffThreadToken);
@@ -2061,7 +2238,13 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
// Module has an error status to be rethrown // Module has an error status to be rethrown
JS::Rooted<JS::Value> error(cx, moduleScript->ErrorToRethrow()); JS::Rooted<JS::Value> error(cx, moduleScript->ErrorToRethrow());
JS_SetPendingException(cx, error); JS_SetPendingException(cx, error);
return NS_OK; // An error is reported by AutoEntryScript.
// For a dynamic import, the promise is rejected. Otherwise an error is
// either reported by AutoEntryScript.
if (request->IsDynamicImport()) {
FinishDynamicImport(cx, request, NS_OK);
}
return NS_OK;
} }
JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord()); JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
@@ -2070,12 +2253,17 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
rv = nsJSUtils::ModuleEvaluate(cx, module); rv = nsJSUtils::ModuleEvaluate(cx, module);
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException()); MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
// Evaluation failed // For a dynamic import, the promise is rejected. Otherwise an error is
rv = NS_OK; // An error is reported by AutoEntryScript. // either reported by AutoEntryScript.
rv = NS_OK;
}
if (request->IsDynamicImport()) {
FinishDynamicImport(cx, request, rv);
} }
} else { } else {
// Update our current script. // Update our current script.
AutoCurrentScriptUpdater scriptUpdater(this, aRequest->mElement); AutoCurrentScriptUpdater scriptUpdater(this, aRequest->Element());
JS::CompileOptions options(cx); JS::CompileOptions options(cx);
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options); rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
@@ -2089,7 +2277,6 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
} }
} }
context->SetProcessingScriptTag(oldProcessingScriptTag);
return rv; return rv;
} }
@@ -2101,6 +2288,7 @@ ScriptLoader::ProcessPendingRequestsAsync()
!mLoadedAsyncRequests.isEmpty() || !mLoadedAsyncRequests.isEmpty() ||
!mNonAsyncExternalScriptInsertedRequests.isEmpty() || !mNonAsyncExternalScriptInsertedRequests.isEmpty() ||
!mDeferRequests.isEmpty() || !mDeferRequests.isEmpty() ||
!mDynamicImportRequests.isEmpty() ||
!mPendingChildLoaders.IsEmpty()) { !mPendingChildLoaders.IsEmpty()) {
nsCOMPtr<nsIRunnable> task = NewRunnableMethod(this, nsCOMPtr<nsIRunnable> task = NewRunnableMethod(this,
&ScriptLoader::ProcessPendingRequests); &ScriptLoader::ProcessPendingRequests);
@@ -2394,7 +2582,7 @@ ScriptLoader::VerifySRI(ScriptLoadRequest* aRequest,
loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp)); loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
nsAutoCString violationURISpec; nsAutoCString violationURISpec;
mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec); mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec);
uint32_t lineNo = aRequest->mElement ? aRequest->mElement->GetScriptLineNumber() : 0; uint32_t lineNo = aRequest->Element() ? aRequest->Element()->GetScriptLineNumber() : 0;
csp->LogViolationDetails( csp->LogViolationDetails(
nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT, nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
NS_ConvertUTF8toUTF16(violationURISpec), NS_ConvertUTF8toUTF16(violationURISpec),
@@ -2414,7 +2602,7 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
* array of blocked tracking nodes under its parent document. * array of blocked tracking nodes under its parent document.
*/ */
if (aResult == NS_ERROR_TRACKING_URI) { if (aResult == NS_ERROR_TRACKING_URI) {
nsCOMPtr<nsIContent> cont = do_QueryInterface(aRequest->mElement); nsCOMPtr<nsIContent> cont = do_QueryInterface(aRequest->Element());
mDocument->AddBlockedTrackingNode(cont); mDocument->AddBlockedTrackingNode(cont);
} }
@@ -2448,13 +2636,30 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
RefPtr<ScriptLoadRequest> req = mXSLTRequests.Steal(aRequest); RefPtr<ScriptLoadRequest> req = mXSLTRequests.Steal(aRequest);
FireScriptAvailable(aResult, req); FireScriptAvailable(aResult, req);
} }
} else if (aRequest->IsModuleRequest() && !aRequest->IsPreload()) { } else if (aRequest->IsPreload()) {
if (aRequest->IsModuleRequest()) {
aRequest->Cancel();
}
if (aRequest->IsTopLevel()) {
MOZ_ALWAYS_TRUE(
mPreloads.RemoveElement(aRequest, PreloadRequestComparator()));
}
MOZ_ASSERT(!aRequest->isInList());
} else if (aRequest->IsModuleRequest()) {
ModuleLoadRequest* modReq = aRequest->AsModuleRequest(); ModuleLoadRequest* modReq = aRequest->AsModuleRequest();
MOZ_ASSERT(!modReq->IsTopLevel()); if (modReq->IsDynamicImport()) {
MOZ_ASSERT(!modReq->isInList()); MOZ_ASSERT(modReq->IsTopLevel());
modReq->Cancel(); if (aRequest->isInList()) {
// A single error is fired for the top level module, so don't use RefPtr<ScriptLoadRequest> req = mDynamicImportRequests.Steal(aRequest);
// FireScriptAvailable here. modReq->Cancel();
FinishDynamicImport(modReq, aResult);
}
} else {
MOZ_ASSERT(!modReq->IsTopLevel());
MOZ_ASSERT(!modReq->isInList());
modReq->Cancel();
// The error is handled for the top level module.
}
} else if (mParserBlockingRequest == aRequest) { } else if (mParserBlockingRequest == aRequest) {
MOZ_ASSERT(!aRequest->isInList()); MOZ_ASSERT(!aRequest->isInList());
mParserBlockingRequest = nullptr; mParserBlockingRequest = nullptr;
@@ -2462,22 +2667,13 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
// Ensure that we treat request->mElement as our current parser-inserted // Ensure that we treat request->mElement as our current parser-inserted
// script while firing onerror on it. // script while firing onerror on it.
MOZ_ASSERT(aRequest->mElement->GetParserCreated()); MOZ_ASSERT(aRequest->Element()->GetParserCreated());
nsCOMPtr<nsIScriptElement> oldParserInsertedScript = nsCOMPtr<nsIScriptElement> oldParserInsertedScript =
mCurrentParserInsertedScript; mCurrentParserInsertedScript;
mCurrentParserInsertedScript = aRequest->mElement; mCurrentParserInsertedScript = aRequest->Element();
FireScriptAvailable(aResult, aRequest); FireScriptAvailable(aResult, aRequest);
ContinueParserAsync(aRequest); ContinueParserAsync(aRequest);
mCurrentParserInsertedScript = oldParserInsertedScript; mCurrentParserInsertedScript = oldParserInsertedScript;
} else if (aRequest->IsPreload()) {
if (aRequest->IsModuleRequest()) {
// If there is an error preloading modules, cancel the load request.
aRequest->Cancel();
}
if (aRequest->IsTopLevel()) {
MOZ_ALWAYS_TRUE(mPreloads.RemoveElement(aRequest, PreloadRequestComparator()));
}
MOZ_ASSERT(!aRequest->isInList());
} else { } else {
// This happens for blocking requests cancelled by ParsingComplete(). // This happens for blocking requests cancelled by ParsingComplete().
MOZ_ASSERT(aRequest->IsCanceled()); MOZ_ASSERT(aRequest->IsCanceled());
@@ -2489,13 +2685,13 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
void void
ScriptLoader::UnblockParser(ScriptLoadRequest* aParserBlockingRequest) ScriptLoader::UnblockParser(ScriptLoadRequest* aParserBlockingRequest)
{ {
aParserBlockingRequest->mElement->UnblockParser(); aParserBlockingRequest->Element()->UnblockParser();
} }
void void
ScriptLoader::ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest) ScriptLoader::ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest)
{ {
aParserBlockingRequest->mElement->ContinueParserAsync(); aParserBlockingRequest->Element()->ContinueParserAsync();
} }
uint32_t uint32_t
@@ -2575,7 +2771,7 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
// If this load was subject to a CORS check, don't flag it with a separate // If this load was subject to a CORS check, don't flag it with a separate
// origin principal, so that it will treat our document's principal as the // origin principal, so that it will treat our document's principal as the
// origin principal. Module loads always use CORS. // origin principal. Module loads always use CORS.
if (!aRequest->IsModuleRequest() && aRequest->mCORSMode == CORS_NONE) { if (!aRequest->IsModuleRequest() && aRequest->CORSMode() == CORS_NONE) {
rv = nsContentUtils::GetSecurityManager()-> rv = nsContentUtils::GetSecurityManager()->
GetChannelResultPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal)); GetChannelResultPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@@ -2594,11 +2790,12 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
mLoadingAsyncRequests.Contains(aRequest) || mLoadingAsyncRequests.Contains(aRequest) ||
mNonAsyncExternalScriptInsertedRequests.Contains(aRequest) || mNonAsyncExternalScriptInsertedRequests.Contains(aRequest) ||
mXSLTRequests.Contains(aRequest) || mXSLTRequests.Contains(aRequest) ||
mDynamicImportRequests.Contains(aRequest) ||
(aRequest->IsModuleRequest() && (aRequest->IsModuleRequest() &&
!aRequest->AsModuleRequest()->IsTopLevel() && !aRequest->AsModuleRequest()->IsTopLevel() &&
!aRequest->isInList()) || !aRequest->isInList()) ||
mPreloads.Contains(aRequest, PreloadRequestComparator()) || mPreloads.Contains(aRequest, PreloadRequestComparator()) ||
mParserBlockingRequest, mParserBlockingRequest == aRequest,
"aRequest should be pending!"); "aRequest should be pending!");
if (aRequest->IsModuleRequest()) { if (aRequest->IsModuleRequest()) {
@@ -2676,6 +2873,13 @@ ScriptLoader::ParsingComplete(bool aTerminated)
mLoadedAsyncRequests.Clear(); mLoadedAsyncRequests.Clear();
mNonAsyncExternalScriptInsertedRequests.Clear(); mNonAsyncExternalScriptInsertedRequests.Clear();
mXSLTRequests.Clear(); mXSLTRequests.Clear();
for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req;
req = req->getNext()) {
req->Cancel();
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
}
if (mParserBlockingRequest) { if (mParserBlockingRequest) {
mParserBlockingRequest->Cancel(); mParserBlockingRequest->Cancel();
mParserBlockingRequest = nullptr; mParserBlockingRequest = nullptr;
@@ -2743,7 +2947,8 @@ ScriptLoader::PreloadURI(nsIURI *aURI,
} }
RefPtr<ScriptLoadRequest> request = RefPtr<ScriptLoadRequest> request =
CreateLoadRequest(scriptKind, aURI, nullptr, 0, CreateLoadRequest(scriptKind, aURI, nullptr,
mDocument->NodePrincipal(),
Element::StringToCORSMode(aCrossOrigin), sriMetadata, Element::StringToCORSMode(aCrossOrigin), sriMetadata,
aReferrerPolicy); aReferrerPolicy);
request->mIsInline = false; request->mIsInline = false;
+82 -21
View File
@@ -48,6 +48,33 @@ enum class ScriptKind {
Module Module
}; };
/*
* Some options used when fetching script resources. This only loosely
* corresponds to HTML's "script fetch options".
*
* These are common to all modules in a module graph, and hence a single
* instance is shared by all ModuleLoadRequest objects in a graph.
*/
class ScriptFetchOptions
{
~ScriptFetchOptions();
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ScriptFetchOptions)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ScriptFetchOptions)
ScriptFetchOptions(mozilla::CORSMode aCORSMode,
mozilla::net::ReferrerPolicy aReferrerPolicy,
nsIScriptElement* aElement,
nsIPrincipal* aTriggeringPrincipal);
const mozilla::CORSMode mCORSMode;
const mozilla::net::ReferrerPolicy mReferrerPolicy;
nsCOMPtr<nsIScriptElement> mElement;
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
};
class ScriptLoadRequest : public nsISupports, class ScriptLoadRequest : public nsISupports,
private mozilla::LinkedListElement<ScriptLoadRequest> private mozilla::LinkedListElement<ScriptLoadRequest>
{ {
@@ -63,16 +90,12 @@ protected:
public: public:
ScriptLoadRequest(ScriptKind aKind, ScriptLoadRequest(ScriptKind aKind,
nsIURI* aURI, nsIURI* aURI,
nsIScriptElement* aElement, ScriptFetchOptions* aFetchOptions,
uint32_t aVersion,
mozilla::CORSMode aCORSMode,
const SRIMetadata& aIntegrity, const SRIMetadata& aIntegrity,
nsIURI* aReferrer, nsIURI* aReferrer)
mozilla::net::ReferrerPolicy aReferrerPolicy)
: mKind(aKind), : mKind(aKind),
mElement(aElement),
mProgress(Progress::Loading),
mScriptMode(ScriptMode::eBlocking), mScriptMode(ScriptMode::eBlocking),
mProgress(Progress::Loading),
mIsInline(true), mIsInline(true),
mHasSourceMapURL(false), mHasSourceMapURL(false),
mInDeferList(false), mInDeferList(false),
@@ -85,13 +108,10 @@ public:
mOffThreadToken(nullptr), mOffThreadToken(nullptr),
mScriptTextBuf(nullptr), mScriptTextBuf(nullptr),
mScriptTextLength(0), mScriptTextLength(0),
mJSVersion(aVersion),
mURI(aURI), mURI(aURI),
mLineNo(1), mLineNo(1),
mCORSMode(aCORSMode),
mIntegrity(aIntegrity), mIntegrity(aIntegrity),
mReferrer(aReferrer), mReferrer(aReferrer)
mReferrerPolicy(aReferrerPolicy)
{ {
} }
@@ -108,16 +128,16 @@ public:
void FireScriptAvailable(nsresult aResult) void FireScriptAvailable(nsresult aResult)
{ {
bool isInlineClassicScript = mIsInline && !IsModuleRequest(); bool isInlineClassicScript = mIsInline && !IsModuleRequest();
mElement->ScriptAvailable(aResult, mElement, isInlineClassicScript, mURI, mLineNo); Element()->ScriptAvailable(aResult, Element(), isInlineClassicScript, mURI, mLineNo);
} }
void FireScriptEvaluated(nsresult aResult) void FireScriptEvaluated(nsresult aResult)
{ {
mElement->ScriptEvaluated(aResult, mElement, mIsInline); Element()->ScriptEvaluated(aResult, Element(), mIsInline);
} }
bool IsPreload() bool IsPreload()
{ {
return mElement == nullptr; return Element() == nullptr;
} }
virtual void Cancel(); virtual void Cancel();
@@ -190,15 +210,42 @@ public:
return true; return true;
} }
mozilla::CORSMode CORSMode() const
{
return mFetchOptions->mCORSMode;
}
mozilla::net::ReferrerPolicy ReferrerPolicy() const
{
return mFetchOptions->mReferrerPolicy;
}
nsIScriptElement* Element() const
{
return mFetchOptions->mElement;
}
nsIPrincipal* TriggeringPrincipal() const
{
return mFetchOptions->mTriggeringPrincipal;
}
void SetElement(nsIScriptElement* aElement)
{
// Called when a preload request is later used for an actual request.
MOZ_ASSERT(aElement);
MOZ_ASSERT(!Element());
mFetchOptions->mElement = aElement;
}
void SetScript(JSScript* aScript);
void MaybeCancelOffThreadScript(); void MaybeCancelOffThreadScript();
using super::getNext; using super::getNext;
using super::isInList; using super::isInList;
const ScriptKind mKind; const ScriptKind mKind; // Whether this is a classic script or a module script.
nsCOMPtr<nsIScriptElement> mElement; ScriptMode mScriptMode; // Whether this is a blocking, defer or async script.
Progress mProgress; // Are we still waiting for a load to complete? Progress mProgress; // Are we still waiting for a load to complete?
ScriptMode mScriptMode; // Whether this script is blocking, deferred or async. bool mScriptFromHead; // Synchronous head script block loading of other non js/css content.
bool mIsInline; // Is the script inline or loaded? bool mIsInline; // Is the script inline or loaded?
bool mHasSourceMapURL; // Does the HTTP header have a source map url? bool mHasSourceMapURL; // Does the HTTP header have a source map url?
bool mInDeferList; // True if we live in mDeferRequests. bool mInDeferList; // True if we live in mDeferRequests.
@@ -212,15 +259,18 @@ public:
nsString mSourceMapURL; // Holds source map url for loaded scripts nsString mSourceMapURL; // Holds source map url for loaded scripts
char16_t* mScriptTextBuf; // Holds script text for non-inline scripts. Don't char16_t* mScriptTextBuf; // Holds script text for non-inline scripts. Don't
size_t mScriptTextLength; // use nsString so we can give ownership to jsapi. size_t mScriptTextLength; // use nsString so we can give ownership to jsapi.
uint32_t mJSVersion;
const nsCOMPtr<nsIURI> mURI; const nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mOriginPrincipal; nsCOMPtr<nsIPrincipal> mOriginPrincipal;
nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing. nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing.
int32_t mLineNo; int32_t mLineNo;
const mozilla::CORSMode mCORSMode;
const SRIMetadata mIntegrity; const SRIMetadata mIntegrity;
const nsCOMPtr<nsIURI> mReferrer; const nsCOMPtr<nsIURI> mReferrer;
const mozilla::net::ReferrerPolicy mReferrerPolicy;
RefPtr<ScriptFetchOptions> mFetchOptions;
// Holds the top-level JSScript that corresponds to the current source, once
// it is parsed, and planned to be saved in the bytecode cache.
JS::Heap<JSScript*> mScript;
}; };
class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest> class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest>
@@ -529,13 +579,20 @@ public:
*/ */
void ClearModuleMap(); void ClearModuleMap();
void StartDynamicImport(ModuleLoadRequest* aRequest);
void FinishDynamicImport(ModuleLoadRequest* aRequest, nsresult aResult);
void FinishDynamicImport(JSContext* aCx, ModuleLoadRequest* aRequest,
nsresult aResult);
private: private:
virtual ~ScriptLoader(); virtual ~ScriptLoader();
void EnsureModuleHooksInitialized();
ScriptLoadRequest* CreateLoadRequest(ScriptKind aKind, ScriptLoadRequest* CreateLoadRequest(ScriptKind aKind,
nsIURI* aURI, nsIURI* aURI,
nsIScriptElement* aElement, nsIScriptElement* aElement,
uint32_t aVersion, nsIPrincipal* aTriggeringPrincipal,
mozilla::CORSMode aCORSMode, mozilla::CORSMode aCORSMode,
const SRIMetadata& aIntegrity, const SRIMetadata& aIntegrity,
mozilla::net::ReferrerPolicy aReferrerPolicy); mozilla::net::ReferrerPolicy aReferrerPolicy);
@@ -609,6 +666,7 @@ private:
nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest); nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest);
nsresult ProcessRequest(ScriptLoadRequest* aRequest); nsresult ProcessRequest(ScriptLoadRequest* aRequest);
void ProcessDynamicImport(ModuleLoadRequest* aRequest);
nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest); nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest);
void FireScriptAvailable(nsresult aResult, void FireScriptAvailable(nsresult aResult,
ScriptLoadRequest* aRequest); ScriptLoadRequest* aRequest);
@@ -663,6 +721,8 @@ private:
RefPtr<mozilla::GenericPromise> RefPtr<mozilla::GenericPromise>
StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent, nsIURI* aURI); StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent, nsIURI* aURI);
void RunScriptWhenSafe(ScriptLoadRequest* aRequest);
nsIDocument* mDocument; // [WEAK] nsIDocument* mDocument; // [WEAK]
nsCOMArray<nsIScriptLoaderObserver> mObservers; nsCOMArray<nsIScriptLoaderObserver> mObservers;
ScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests; ScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests;
@@ -672,6 +732,7 @@ private:
ScriptLoadRequestList mLoadedAsyncRequests; ScriptLoadRequestList mLoadedAsyncRequests;
ScriptLoadRequestList mDeferRequests; ScriptLoadRequestList mDeferRequests;
ScriptLoadRequestList mXSLTRequests; ScriptLoadRequestList mXSLTRequests;
ScriptLoadRequestList mDynamicImportRequests;
RefPtr<ScriptLoadRequest> mParserBlockingRequest; RefPtr<ScriptLoadRequest> mParserBlockingRequest;
// In mRequests, the additional information here is stored by the element. // In mRequests, the additional information here is stored by the element.