summaryrefslogtreecommitdiffstats
path: root/dom/script
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2020-08-31 05:54:39 +0000
committerMoonchild <moonchild@palemoon.org>2020-08-31 05:54:39 +0000
commita6f632714fcb1be3dd00b0fc76fbf6bfc693155b (patch)
treeb04c82f9af4a0d288a6d4350d774ad8fe6dac903 /dom/script
parent2ed0607c747b21cadaf7401d4ba706097578e74d (diff)
parentb28effe2ea93e43e362f7ce263d23b55adcb6da7 (diff)
downloadUXP-a6f632714fcb1be3dd00b0fc76fbf6bfc693155b.tar
UXP-a6f632714fcb1be3dd00b0fc76fbf6bfc693155b.tar.gz
UXP-a6f632714fcb1be3dd00b0fc76fbf6bfc693155b.tar.lz
UXP-a6f632714fcb1be3dd00b0fc76fbf6bfc693155b.tar.xz
UXP-a6f632714fcb1be3dd00b0fc76fbf6bfc693155b.zip
Merge branch 'redwood' into releaseRELBASE_20200831
Diffstat (limited to 'dom/script')
-rw-r--r--dom/script/ModuleLoadRequest.cpp45
-rw-r--r--dom/script/ModuleLoadRequest.h33
-rw-r--r--dom/script/ModuleScript.cpp43
-rw-r--r--dom/script/ModuleScript.h12
-rw-r--r--dom/script/ScriptElement.cpp8
-rw-r--r--dom/script/ScriptLoader.cpp680
-rw-r--r--dom/script/ScriptLoader.h89
-rw-r--r--dom/script/nsIScriptElement.h29
-rw-r--r--dom/script/nsIScriptLoaderObserver.idl9
9 files changed, 560 insertions, 388 deletions
diff --git a/dom/script/ModuleLoadRequest.cpp b/dom/script/ModuleLoadRequest.cpp
index d62214304..743f30fb9 100644
--- a/dom/script/ModuleLoadRequest.cpp
+++ b/dom/script/ModuleLoadRequest.cpp
@@ -17,26 +17,54 @@ NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest,
mBaseURL,
mLoader,
- mParent,
mModuleScript,
mImports)
NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
-ModuleLoadRequest::ModuleLoadRequest(nsIScriptElement* aElement,
+ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI,
+ nsIScriptElement* aElement,
uint32_t aVersion,
CORSMode aCORSMode,
const SRIMetadata &aIntegrity,
+ nsIURI* aReferrer,
+ mozilla::net::ReferrerPolicy aReferrerPolicy,
ScriptLoader* aLoader)
: ScriptLoadRequest(ScriptKind::Module,
+ aURI,
aElement,
aVersion,
aCORSMode,
- aIntegrity),
+ aIntegrity,
+ aReferrer,
+ aReferrerPolicy),
mIsTopLevel(true),
- mLoader(aLoader)
-{}
+ mLoader(aLoader),
+ mVisitedSet(new VisitedURLSet())
+{
+ mVisitedSet->PutEntry(aURI);
+}
+
+ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI,
+ ModuleLoadRequest* aParent)
+ : ScriptLoadRequest(ScriptKind::Module,
+ aURI,
+ aParent->mElement,
+ aParent->mJSVersion,
+ aParent->mCORSMode,
+ SRIMetadata(),
+ aParent->mURI,
+ aParent->mReferrerPolicy),
+ mIsTopLevel(false),
+ mLoader(aParent->mLoader),
+ mVisitedSet(aParent->mVisitedSet)
+{
+ MOZ_ASSERT(mVisitedSet->Contains(aURI));
+
+ mIsInline = false;
+ mScriptMode = aParent->mScriptMode;
+}
void ModuleLoadRequest::Cancel()
{
@@ -83,7 +111,7 @@ ModuleLoadRequest::ModuleLoaded()
// been loaded.
mModuleScript = mLoader->GetFetchedModule(mURI);
- if (!mModuleScript || mModuleScript->IsErrored()) {
+ if (!mModuleScript || mModuleScript->HasParseError()) {
ModuleErrored();
return;
}
@@ -95,7 +123,7 @@ void
ModuleLoadRequest::ModuleErrored()
{
mLoader->CheckModuleDependenciesLoaded(this);
- MOZ_ASSERT(!mModuleScript || mModuleScript->IsErrored());
+ MOZ_ASSERT(!mModuleScript || mModuleScript->HasParseError());
CancelImports();
SetReady();
@@ -132,8 +160,7 @@ ModuleLoadRequest::LoadFinished()
{
mLoader->ProcessLoadedModuleTree(this);
mLoader = nullptr;
- mParent = nullptr;
}
} // dom namespace
-} // mozilla namespace \ No newline at end of file
+} // mozilla namespace
diff --git a/dom/script/ModuleLoadRequest.h b/dom/script/ModuleLoadRequest.h
index 7b06dd2cf..eefb7dad5 100644
--- a/dom/script/ModuleLoadRequest.h
+++ b/dom/script/ModuleLoadRequest.h
@@ -8,6 +8,7 @@
#define mozilla_dom_ModuleLoadRequest_h
#include "mozilla/dom/ScriptLoader.h"
+#include "nsURIHashKey.h"
#include "mozilla/MozPromise.h"
namespace mozilla {
@@ -16,6 +17,16 @@ namespace dom {
class ModuleScript;
class ScriptLoader;
+// A reference counted set of URLs we have visited in the process of loading a
+// module graph.
+class VisitedURLSet : public nsTHashtable<nsURIHashKey>
+{
+ NS_INLINE_DECL_REFCOUNTING(VisitedURLSet)
+
+private:
+ ~VisitedURLSet() = default;
+};
+
// A load request for a module, created for every top level module script and
// every module import. Load request can share a ModuleScript if there are
// multiple imports of the same module.
@@ -31,12 +42,20 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
- ModuleLoadRequest(nsIScriptElement* aElement,
+ // Create a top-level module load request.
+ ModuleLoadRequest(nsIURI* aURI,
+ nsIScriptElement* aElement,
uint32_t aVersion,
CORSMode aCORSMode,
const SRIMetadata& aIntegrity,
+ nsIURI* aReferrer,
+ mozilla::net::ReferrerPolicy,
ScriptLoader* aLoader);
+ // Create a module load request for an imported module.
+ ModuleLoadRequest(nsIURI* aURI,
+ ModuleLoadRequest* aParent);
+
bool IsTopLevel() const {
return mIsTopLevel;
}
@@ -55,7 +74,7 @@ private:
public:
// Is this a request for a top level module script or an import?
- bool mIsTopLevel;
+ const bool mIsTopLevel;
// The base URL used for resolving relative module imports.
nsCOMPtr<nsIURI> mBaseURL;
@@ -64,10 +83,6 @@ public:
// finishes.
RefPtr<ScriptLoader> mLoader;
- // The importing module, or nullptr for top level module scripts. Used to
- // implement the ancestor list checked when fetching module dependencies.
- RefPtr<ModuleLoadRequest> mParent;
-
// Set to a module script object after a successful load or nullptr on
// failure.
RefPtr<ModuleScript> mModuleScript;
@@ -79,9 +94,13 @@ public:
// Array of imported modules.
nsTArray<RefPtr<ModuleLoadRequest>> mImports;
+
+ // Set of module URLs visited while fetching the module graph this request is
+ // part of.
+ RefPtr<VisitedURLSet> mVisitedSet;
};
} // dom namespace
} // mozilla namespace
-#endif // mozilla_dom_ModuleLoadRequest_h \ No newline at end of file
+#endif // mozilla_dom_ModuleLoadRequest_h
diff --git a/dom/script/ModuleScript.cpp b/dom/script/ModuleScript.cpp
index 28b97a3cb..1bf9d0b0f 100644
--- a/dom/script/ModuleScript.cpp
+++ b/dom/script/ModuleScript.cpp
@@ -26,7 +26,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
tmp->UnlinkModuleRecord();
- tmp->mError.setUndefined();
+ tmp->mParseError.setUndefined();
+ tmp->mErrorToRethrow.setUndefined();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
@@ -35,7 +36,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mError)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
@@ -48,7 +50,8 @@ ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL)
MOZ_ASSERT(mLoader);
MOZ_ASSERT(mBaseURL);
MOZ_ASSERT(!mModuleRecord);
- MOZ_ASSERT(mError.isUndefined());
+ MOZ_ASSERT(!HasParseError());
+ MOZ_ASSERT(!HasErrorToRethrow());
}
void
@@ -74,7 +77,8 @@ void
ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
{
MOZ_ASSERT(!mModuleRecord);
- MOZ_ASSERT(mError.isUndefined());
+ MOZ_ASSERT(!HasParseError());
+ MOZ_ASSERT(!HasErrorToRethrow());
mModuleRecord = aModuleRecord;
@@ -85,37 +89,24 @@ ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
}
void
-ModuleScript::SetPreInstantiationError(const JS::Value& aError)
+ModuleScript::SetParseError(const JS::Value& aError)
{
MOZ_ASSERT(!aError.isUndefined());
+ MOZ_ASSERT(!HasParseError());
+ MOZ_ASSERT(!HasErrorToRethrow());
UnlinkModuleRecord();
- mError = aError;
-
+ mParseError = aError;
HoldJSObjects(this);
}
-bool
-ModuleScript::IsErrored() const
-{
- if (!mModuleRecord) {
- MOZ_ASSERT(!mError.isUndefined());
- return true;
- }
-
- return JS::IsModuleErrored(mModuleRecord);
-}
-
-JS::Value
-ModuleScript::Error() const
+void
+ModuleScript::SetErrorToRethrow(const JS::Value& aError)
{
- MOZ_ASSERT(IsErrored());
-
- if (!mModuleRecord) {
- return mError;
- }
+ MOZ_ASSERT(!aError.isUndefined());
+ MOZ_ASSERT(!HasErrorToRethrow());
- return JS::GetModuleError(mModuleRecord);
+ mErrorToRethrow = aError;
}
} // dom namespace
diff --git a/dom/script/ModuleScript.h b/dom/script/ModuleScript.h
index 571359859..f765aa0fa 100644
--- a/dom/script/ModuleScript.h
+++ b/dom/script/ModuleScript.h
@@ -23,7 +23,8 @@ class ModuleScript final : public nsISupports
RefPtr<ScriptLoader> mLoader;
nsCOMPtr<nsIURI> mBaseURL;
JS::Heap<JSObject*> mModuleRecord;
- JS::Heap<JS::Value> mError;
+ JS::Heap<JS::Value> mParseError;
+ JS::Heap<JS::Value> mErrorToRethrow;
~ModuleScript();
@@ -35,14 +36,17 @@ public:
nsIURI* aBaseURL);
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
- void SetPreInstantiationError(const JS::Value& aError);
+ void SetParseError(const JS::Value& aError);
+ void SetErrorToRethrow(const JS::Value& aError);
ScriptLoader* Loader() const { return mLoader; }
JSObject* ModuleRecord() const { return mModuleRecord; }
nsIURI* BaseURL() const { return mBaseURL; }
- bool IsErrored() const;
- JS::Value Error() const;
+ JS::Value ParseError() const { return mParseError; }
+ JS::Value ErrorToRethrow() const { return mErrorToRethrow; }
+ bool HasParseError() const { return !mParseError.isUndefined(); }
+ bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
void UnlinkModuleRecord();
};
diff --git a/dom/script/ScriptElement.cpp b/dom/script/ScriptElement.cpp
index 0cb17dcb0..eb20dbf32 100644
--- a/dom/script/ScriptElement.cpp
+++ b/dom/script/ScriptElement.cpp
@@ -21,11 +21,11 @@ using namespace mozilla::dom;
NS_IMETHODIMP
ScriptElement::ScriptAvailable(nsresult aResult,
nsIScriptElement *aElement,
- bool aIsInline,
+ bool aIsInlineClassicScript,
nsIURI *aURI,
int32_t aLineNo)
{
- if (!aIsInline && NS_FAILED(aResult)) {
+ if (!aIsInlineClassicScript && NS_FAILED(aResult)) {
nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
if (parser) {
parser->PushDefinedInsertionPoint();
@@ -128,11 +128,11 @@ ScriptElement::MaybeProcessScript()
return false;
}
- FreezeUriAsyncDefer();
+ nsIDocument* ownerDoc = cont->OwnerDoc();
+ FreezeExecutionAttrs(ownerDoc);
mAlreadyStarted = true;
- nsIDocument* ownerDoc = cont->OwnerDoc();
nsCOMPtr<nsIParser> parser = ((nsIScriptElement*) this)->GetCreatorParser();
if (parser) {
nsCOMPtr<nsIContentSink> sink = parser->GetContentSink();
diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
index a53098974..989301b91 100644
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -140,6 +140,18 @@ ScriptLoadRequest::AsModuleRequest()
return static_cast<ModuleLoadRequest*>(this);
}
+void
+ScriptLoadRequest::SetScriptMode(bool aDeferAttr, bool aAsyncAttr)
+{
+ if (aAsyncAttr) {
+ mScriptMode = ScriptMode::eAsync;
+ } else if (aDeferAttr || IsModuleRequest()) {
+ mScriptMode = ScriptMode::eDeferred;
+ } else {
+ mScriptMode = ScriptMode::eBlocking;
+ }
+}
+
//////////////////////////////////////////////////////////////
// ScriptLoadRequestList
@@ -299,8 +311,12 @@ ScriptLoader::~ScriptLoader()
// <script for=... event=...> element.
static bool
-IsScriptEventHandler(nsIContent* aScriptElement)
+IsScriptEventHandler(ScriptKind kind, nsIContent* aScriptElement)
{
+ if (kind != ScriptKind::Classic) {
+ return false;
+ }
+
if (!aScriptElement->IsHTMLElement()) {
return false;
}
@@ -375,25 +391,12 @@ ScriptLoader::CheckContentPolicy(nsIDocument* aDocument,
}
bool
-ScriptLoader::ModuleScriptsEnabled()
-{
- static bool sEnabledForContent = false;
- static bool sCachedPref = false;
- if (!sCachedPref) {
- sCachedPref = true;
- Preferences::AddBoolVarCache(&sEnabledForContent, "dom.moduleScripts.enabled", false);
- }
-
- return nsContentUtils::IsChromeDoc(mDocument) || sEnabledForContent;
-}
-
-bool
-ScriptLoader::ModuleMapContainsModule(ModuleLoadRequest *aRequest) const
+ScriptLoader::ModuleMapContainsURL(nsIURI* aURL) const
{
// Returns whether we have fetched, or are currently fetching, a module script
- // for the request's URL.
- return mFetchingModules.Contains(aRequest->mURI) ||
- mFetchedModules.Contains(aRequest->mURI);
+ // for a URL.
+ return mFetchingModules.Contains(aURL) ||
+ mFetchedModules.Contains(aURL);
}
bool
@@ -410,7 +413,7 @@ ScriptLoader::SetModuleFetchStarted(ModuleLoadRequest *aRequest)
// Update the module map to indicate that a module is currently being fetched.
MOZ_ASSERT(aRequest->IsLoading());
- MOZ_ASSERT(!ModuleMapContainsModule(aRequest));
+ MOZ_ASSERT(!ModuleMapContainsURL(aRequest->mURI));
mFetchingModules.Put(aRequest->mURI, nullptr);
}
@@ -443,21 +446,21 @@ ScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *
}
RefPtr<GenericPromise>
-ScriptLoader::WaitForModuleFetch(ModuleLoadRequest *aRequest)
+ScriptLoader::WaitForModuleFetch(nsIURI* aURL)
{
- MOZ_ASSERT(ModuleMapContainsModule(aRequest));
+ MOZ_ASSERT(ModuleMapContainsURL(aURL));
RefPtr<GenericPromise::Private> promise;
- if (mFetchingModules.Get(aRequest->mURI, getter_AddRefs(promise))) {
+ if (mFetchingModules.Get(aURL, getter_AddRefs(promise))) {
if (!promise) {
promise = new GenericPromise::Private(__func__);
- mFetchingModules.Put(aRequest->mURI, promise);
+ mFetchingModules.Put(aURL, promise);
}
return promise;
}
RefPtr<ModuleScript> ms;
- MOZ_ALWAYS_TRUE(mFetchedModules.Get(aRequest->mURI, getter_AddRefs(ms)));
+ MOZ_ALWAYS_TRUE(mFetchedModules.Get(aURL, getter_AddRefs(ms)));
if (!ms) {
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
@@ -482,8 +485,6 @@ ScriptLoader::ProcessFetchedModuleSource(ModuleLoadRequest* aRequest)
nsresult rv = CreateModuleScript(aRequest);
MOZ_ASSERT(NS_FAILED(rv) == !aRequest->mModuleScript);
- SetModuleFetchFinishedAndResumeWaitingRequests(aRequest, rv);
-
free(aRequest->mScriptTextBuf);
aRequest->mScriptTextBuf = nullptr;
aRequest->mScriptTextLength = 0;
@@ -493,7 +494,11 @@ ScriptLoader::ProcessFetchedModuleSource(ModuleLoadRequest* aRequest)
return rv;
}
- if (!aRequest->mModuleScript->IsErrored()) {
+ if (!aRequest->mIsInline) {
+ SetModuleFetchFinishedAndResumeWaitingRequests(aRequest, rv);
+ }
+
+ if (!aRequest->mModuleScript->HasParseError()) {
StartFetchingModuleDependencies(aRequest);
}
@@ -501,7 +506,7 @@ ScriptLoader::ProcessFetchedModuleSource(ModuleLoadRequest* aRequest)
}
static nsresult
-ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>& aUrls);
+ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>* aUrlsOut);
nsresult
ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
@@ -528,7 +533,6 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
nsresult rv;
{
// Update our current script.
- AutoCurrentScriptUpdater scriptUpdater(this, aRequest->mElement);
Maybe<AutoCurrentScriptUpdater> masterScriptUpdater;
nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
if (master != mDocument) {
@@ -568,7 +572,7 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
return NS_ERROR_FAILURE;
}
- moduleScript->SetPreInstantiationError(error);
+ moduleScript->SetParseError(error);
aRequest->ModuleErrored();
return NS_OK;
}
@@ -577,11 +581,8 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
// Validate requested modules and treat failure to resolve module specifiers
// the same as a parse error.
- nsCOMArray<nsIURI> urls;
- rv = ResolveRequestedModules(aRequest, urls);
+ rv = ResolveRequestedModules(aRequest, nullptr);
if (NS_FAILED(rv)) {
- // ResolveRequestedModules sets pre-instanitation error on failure.
- MOZ_ASSERT(moduleScript->IsErrored());
aRequest->ModuleErrored();
return NS_OK;
}
@@ -627,7 +628,7 @@ HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
return NS_ERROR_OUT_OF_MEMORY;
}
- aScript->SetPreInstantiationError(error);
+ aScript->SetParseError(error);
return NS_OK;
}
@@ -667,33 +668,7 @@ ResolveModuleSpecifier(ModuleScript* aScript,
}
static nsresult
-RequestedModuleIsInAncestorList(ModuleLoadRequest* aRequest, nsIURI* aURL, bool* aResult)
-{
- const size_t ImportDepthLimit = 100;
-
- *aResult = false;
- size_t depth = 0;
- while (aRequest) {
- if (depth++ == ImportDepthLimit) {
- return NS_ERROR_FAILURE;
- }
-
- bool equal;
- nsresult rv = aURL->Equals(aRequest->mURI, &equal);
- NS_ENSURE_SUCCESS(rv, rv);
- if (equal) {
- *aResult = true;
- return NS_OK;
- }
-
- aRequest = aRequest->mParent;
- }
-
- return NS_OK;
-}
-
-static nsresult
-ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls)
+ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>* aUrlsOut)
{
ModuleScript* ms = aRequest->mModuleScript;
@@ -723,7 +698,6 @@ ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls)
}
// Let url be the result of resolving a module specifier given module script and requested.
- ModuleScript* ms = aRequest->mModuleScript;
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier);
if (!uri) {
nsresult rv = HandleResolveFailure(cx, ms, specifier);
@@ -731,11 +705,8 @@ ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls)
return NS_ERROR_FAILURE;
}
- bool isAncestor;
- nsresult rv = RequestedModuleIsInAncestorList(aRequest, uri, &isAncestor);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!isAncestor) {
- aUrls.AppendElement(uri.forget());
+ if (aUrlsOut) {
+ aUrlsOut->AppendElement(uri.forget());
}
}
@@ -746,20 +717,36 @@ void
ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
{
MOZ_ASSERT(aRequest->mModuleScript);
- MOZ_ASSERT(!aRequest->mModuleScript->IsErrored());
+ MOZ_ASSERT(!aRequest->mModuleScript->HasParseError());
MOZ_ASSERT(!aRequest->IsReadyToRun());
+ auto visitedSet = aRequest->mVisitedSet;
+ MOZ_ASSERT(visitedSet->Contains(aRequest->mURI));
+
aRequest->mProgress = ModuleLoadRequest::Progress::FetchingImports;
nsCOMArray<nsIURI> urls;
- nsresult rv = ResolveRequestedModules(aRequest, urls);
+ nsresult rv = ResolveRequestedModules(aRequest, &urls);
if (NS_FAILED(rv)) {
aRequest->ModuleErrored();
return;
}
- if (urls.Length() == 0) {
- // There are no descendents to load so this request is ready.
+ // Remove already visited URLs from the list. Put unvisited URLs into the
+ // visited set.
+ int32_t i = 0;
+ while (i < urls.Count()) {
+ nsIURI* url = urls[i];
+ if (visitedSet->Contains(url)) {
+ urls.RemoveObjectAt(i);
+ } else {
+ visitedSet->PutEntry(url);
+ i++;
+ }
+ }
+
+ if (urls.Count() == 0) {
+ // There are no descendants to load so this request is ready.
aRequest->DependenciesLoaded();
return;
}
@@ -782,20 +769,14 @@ ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
}
RefPtr<GenericPromise>
-ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest,
+ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent,
nsIURI* aURI)
{
MOZ_ASSERT(aURI);
- RefPtr<ModuleLoadRequest> childRequest =
- new ModuleLoadRequest(aRequest->mElement, aRequest->mJSVersion,
- aRequest->mCORSMode, aRequest->mIntegrity, this);
+ RefPtr<ModuleLoadRequest> childRequest = new ModuleLoadRequest(aURI, aParent);
- childRequest->mIsTopLevel = false;
- childRequest->mURI = aURI;
- childRequest->mIsInline = false;
- childRequest->mReferrerPolicy = aRequest->mReferrerPolicy;
- childRequest->mParent = aRequest;
+ aParent->mImports.AppendElement(childRequest);
RefPtr<GenericPromise> ready = childRequest->mReady.Ensure(__func__);
@@ -806,29 +787,24 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest,
return ready;
}
- aRequest->mImports.AppendElement(childRequest);
return ready;
}
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
-bool
-HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
+JSObject*
+HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
+ JS::Handle<JSString*> aSpecifier)
{
- MOZ_ASSERT(argc == 2);
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
- JS::Rooted<JSObject*> module(aCx, &args[0].toObject());
- JS::Rooted<JSString*> specifier(aCx, args[1].toString());
-
// Let referencing module script be referencingModule.[[HostDefined]].
- JS::Value value = JS::GetModuleHostDefinedField(module);
+ JS::Value value = JS::GetModuleHostDefinedField(aModule);
auto script = static_cast<ModuleScript*>(value.toPrivate());
- MOZ_ASSERT(script->ModuleRecord() == module);
+ MOZ_ASSERT(script->ModuleRecord() == aModule);
// Let url be the result of resolving a module specifier given referencing
// module script and specifier.
nsAutoJSString string;
- if (!string.init(aCx, specifier)) {
- return false;
+ if (!string.init(aCx, aSpecifier)) {
+ return nullptr;
}
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
@@ -843,62 +819,79 @@ HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
ModuleScript* ms = script->Loader()->GetFetchedModule(uri);
MOZ_ASSERT(ms, "Resolved module not found in module map");
- MOZ_ASSERT(!ms->IsErrored());
+ MOZ_ASSERT(!ms->HasParseError());
+ MOZ_ASSERT(ms->ModuleRecord());
- *vp = JS::ObjectValue(*ms->ModuleRecord());
- return true;
+ return ms->ModuleRecord();
}
-static nsresult
+static void
EnsureModuleResolveHook(JSContext* aCx)
{
- if (JS::GetModuleResolveHook(aCx)) {
- return NS_OK;
- }
-
- JS::Rooted<JSFunction*> func(aCx);
- func = JS_NewFunction(aCx, HostResolveImportedModule, 2, 0,
- "HostResolveImportedModule");
- if (!func) {
- return NS_ERROR_FAILURE;
+ JSRuntime* rt = JS_GetRuntime(aCx);
+ if (JS::GetModuleResolveHook(rt)) {
+ return;
}
- JS::SetModuleResolveHook(aCx, func);
- return NS_OK;
+ JS::SetModuleResolveHook(rt, HostResolveImportedModule);
}
void
ScriptLoader::CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest)
{
RefPtr<ModuleScript> moduleScript = aRequest->mModuleScript;
- if (moduleScript && !moduleScript->IsErrored()) {
- for (auto childRequest : aRequest->mImports) {
- ModuleScript* childScript = childRequest->mModuleScript;
- if (!childScript) {
- // Load error
- aRequest->mModuleScript = nullptr;
- return;
- } else if (childScript->IsErrored()) {
- // Script error
- moduleScript->SetPreInstantiationError(childScript->Error());
- return;
- }
+ if (!moduleScript || moduleScript->HasParseError()) {
+ return;
+ }
+
+ for (auto childRequest : aRequest->mImports) {
+ ModuleScript* childScript = childRequest->mModuleScript;
+ if (!childScript) {
+ aRequest->mModuleScript = nullptr;
+ // Load error on script load request; bail.
+ return;
}
}
}
+class ScriptRequestProcessor : public Runnable
+{
+private:
+ RefPtr<ScriptLoader> mLoader;
+ RefPtr<ScriptLoadRequest> mRequest;
+public:
+ ScriptRequestProcessor(ScriptLoader* aLoader,
+ ScriptLoadRequest* aRequest)
+ : mLoader(aLoader)
+ , mRequest(aRequest)
+ {}
+ NS_IMETHOD Run() override
+ {
+ return mLoader->ProcessRequest(mRequest);
+ }
+};
+
void
ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
{
if (aRequest->IsTopLevel()) {
ModuleScript* moduleScript = aRequest->mModuleScript;
- if (moduleScript && !moduleScript->IsErrored()) {
+ if (moduleScript && !moduleScript->HasErrorToRethrow()) {
if (!InstantiateModuleTree(aRequest)) {
aRequest->mModuleScript = nullptr;
}
}
- MaybeMoveToLoadedList(aRequest);
- ProcessPendingRequests();
+
+ if (aRequest->mIsInline &&
+ aRequest->mElement->GetParserCreated() == NOT_FROM_PARSER)
+ {
+ MOZ_ASSERT(!aRequest->isInList());
+ nsContentUtils::AddScriptRunner(
+ new ScriptRequestProcessor(this, aRequest));
+ } else {
+ MaybeMoveToLoadedList(aRequest);
+ ProcessPendingRequests();
+ }
}
if (aRequest->mWasCompiledOMT) {
@@ -906,6 +899,28 @@ ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
}
}
+JS::Value
+ScriptLoader::FindFirstParseError(ModuleLoadRequest* aRequest)
+{
+ MOZ_ASSERT(aRequest);
+
+ ModuleScript* moduleScript = aRequest->mModuleScript;
+ MOZ_ASSERT(moduleScript);
+
+ if (moduleScript->HasParseError()) {
+ return moduleScript->ParseError();
+ }
+
+ for (ModuleLoadRequest* childRequest : aRequest->mImports) {
+ JS::Value error = FindFirstParseError(childRequest);
+ if (!error.isUndefined()) {
+ return error;
+ }
+ }
+
+ return JS::UndefinedValue();
+}
+
bool
ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
{
@@ -916,6 +931,14 @@ ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
ModuleScript* moduleScript = aRequest->mModuleScript;
MOZ_ASSERT(moduleScript);
+
+ JS::Value parseError = FindFirstParseError(aRequest);
+ if (!parseError.isUndefined()) {
+ // Parse error found in the requested script
+ moduleScript->SetErrorToRethrow(parseError);
+ return true;
+ }
+
MOZ_ASSERT(moduleScript->ModuleRecord());
nsAutoMicroTask mt;
@@ -924,8 +947,7 @@ ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
return false;
}
- nsresult rv = EnsureModuleResolveHook(jsapi.cx());
- NS_ENSURE_SUCCESS(rv, false);
+ EnsureModuleResolveHook(jsapi.cx());
JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord());
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module));
@@ -937,7 +959,7 @@ ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
return false;
}
MOZ_ASSERT(!exception.isUndefined());
- // Ignore the exception. It will be recorded in the module record.
+ moduleScript->SetErrorToRethrow(exception);
}
return true;
@@ -959,8 +981,8 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
// Check whether the module has been fetched or is currently being fetched,
// and if so wait for it.
ModuleLoadRequest* request = aRequest->AsModuleRequest();
- if (ModuleMapContainsModule(request)) {
- WaitForModuleFetch(request)
+ if (ModuleMapContainsURL(request->mURI)) {
+ WaitForModuleFetch(request->mURI)
->Then(AbstractThread::GetCurrent(), __func__, request,
&ModuleLoadRequest::ModuleLoaded,
&ModuleLoadRequest::LoadFailed);
@@ -1026,16 +1048,14 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
NS_ENSURE_SUCCESS(rv, rv);
- nsIScriptElement *script = aRequest->mElement;
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
if (cos) {
- if (aScriptFromHead &&
- !(script && (script->GetScriptAsync() || script->GetScriptDeferred()))) {
+ if (aScriptFromHead && aRequest->IsBlockingScript()) {
// synchronous head scripts block lading of most other non js/css
// content such as images
cos->AddClassFlags(nsIClassOfService::Leader);
- } else if (!(script && script->GetScriptDeferred())) {
+ } else if (!aRequest->IsDeferredScript()) {
// other scripts are neither blocked nor prioritized unless marked deferred
cos->AddClassFlags(nsIClassOfService::Unblocked);
}
@@ -1047,7 +1067,7 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("*/*"),
false);
- httpChannel->SetReferrerWithPolicy(mDocument->GetDocumentURI(),
+ httpChannel->SetReferrerWithPolicy(aRequest->mReferrer,
aRequest->mReferrerPolicy);
nsCOMPtr<nsIHttpChannelInternal> internalChannel(do_QueryInterface(httpChannel));
@@ -1095,23 +1115,6 @@ ScriptLoader::PreloadURIComparator::Equals(const PreloadInfo &aPi,
same;
}
-class ScriptRequestProcessor : public Runnable
-{
-private:
- RefPtr<ScriptLoader> mLoader;
- RefPtr<ScriptLoadRequest> mRequest;
-public:
- ScriptRequestProcessor(ScriptLoader* aLoader,
- ScriptLoadRequest* aRequest)
- : mLoader(aLoader)
- , mRequest(aRequest)
- {}
- NS_IMETHOD Run() override
- {
- return mLoader->ProcessRequest(mRequest);
- }
-};
-
static inline bool
ParseTypeAttribute(const nsAString& aType, JSVersion* aVersion)
{
@@ -1176,17 +1179,24 @@ CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument)
ScriptLoadRequest*
ScriptLoader::CreateLoadRequest(ScriptKind aKind,
+ nsIURI* aURI,
nsIScriptElement* aElement,
uint32_t aVersion, CORSMode aCORSMode,
- const SRIMetadata &aIntegrity)
+ const SRIMetadata& aIntegrity,
+ mozilla::net::ReferrerPolicy aReferrerPolicy)
{
+ nsIURI* referrer = mDocument->GetDocumentURI();
+
if (aKind == ScriptKind::Classic) {
- return new ScriptLoadRequest(aKind, aElement, aVersion, aCORSMode,
- aIntegrity);
+ return new ScriptLoadRequest(aKind, aURI, aElement,
+ aVersion, aCORSMode,
+ aIntegrity,
+ referrer, aReferrerPolicy);
}
MOZ_ASSERT(aKind == ScriptKind::Module);
- return new ModuleLoadRequest(aElement, aVersion, aCORSMode, aIntegrity, this);
+ return new ModuleLoadRequest(aURI, aElement, aVersion, aCORSMode,
+ aIntegrity, referrer, aReferrerPolicy, this);
}
bool
@@ -1204,35 +1214,36 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement);
+ nsAutoString type;
+ bool hasType = aElement->GetScriptType(type);
+
+ ScriptKind scriptKind = aElement->GetScriptIsModule() ?
+ ScriptKind::Module :
+ ScriptKind::Classic;
+
// Step 13. Check that the script is not an eventhandler
- if (IsScriptEventHandler(scriptContent)) {
+ if (IsScriptEventHandler(scriptKind, scriptContent)) {
return false;
}
JSVersion version = JSVERSION_DEFAULT;
- // Check the type attribute to determine language and version.
- // If type exists, it trumps the deprecated 'language='
- nsAutoString type;
- bool hasType = aElement->GetScriptType(type);
-
- ScriptKind scriptKind = ScriptKind::Classic;
- if (!type.IsEmpty()) {
- if (ModuleScriptsEnabled() && type.LowerCaseEqualsASCII("module")) {
- scriptKind = ScriptKind::Module;
- } else {
+ // For classic scripts, check the type attribute to determine language and
+ // version. If type exists, it trumps the deprecated 'language='
+ if (scriptKind == ScriptKind::Classic) {
+ if (!type.IsEmpty()) {
NS_ENSURE_TRUE(ParseTypeAttribute(type, &version), false);
- }
- } else if (!hasType) {
- // no 'type=' element
- // "language" is a deprecated attribute of HTML, so we check it only for
- // HTML script elements.
- if (scriptContent->IsHTMLElement()) {
- nsAutoString language;
- scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::language, language);
- if (!language.IsEmpty()) {
- if (!nsContentUtils::IsJavaScriptLanguage(language)) {
- return false;
+ } else if (!hasType) {
+ // no 'type=' element
+ // "language" is a deprecated attribute of HTML, so we check it only for
+ // HTML script elements.
+ if (scriptContent->IsHTMLElement()) {
+ nsAutoString language;
+ scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::language, language);
+ if (!language.IsEmpty()) {
+ if (!nsContentUtils::IsJavaScriptLanguage(language)) {
+ return false;
+ }
}
}
}
@@ -1242,7 +1253,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
// the nomodule attribute will be ignored".
// "The nomodule attribute must not be specified on module scripts (and will
// be ignored if it is)."
- if (ModuleScriptsEnabled() &&
+ if (mDocument->ModuleScriptsEnabled() &&
scriptKind == ScriptKind::Classic &&
scriptContent->IsHTMLElement() &&
scriptContent->HasAttr(kNameSpaceID_None, nsGkAtoms::nomodule)) {
@@ -1252,6 +1263,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
// Step 15. and later in the HTML5 spec
nsresult rv = NS_OK;
RefPtr<ScriptLoadRequest> request;
+ mozilla::net::ReferrerPolicy ourRefPolicy = mDocument->GetReferrerPolicy();
if (aElement->GetScriptExternal()) {
// external script
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
@@ -1264,7 +1276,6 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
}
// Double-check that the preload matches what we're asked to load now.
- mozilla::net::ReferrerPolicy ourRefPolicy = mDocument->GetReferrerPolicy();
CORSMode ourCORSMode = aElement->GetCORSMode();
nsTArray<PreloadInfo>::index_type i =
mPreloads.IndexOf(scriptURI.get(), 0, PreloadURIComparator());
@@ -1297,8 +1308,15 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
}
}
- if (!request) {
- // no usable preload
+ if (request) {
+ // Use a preload request.
+
+ // It's possible these attributes changed since we started the preload, so
+ // update them here.
+ request->SetScriptMode(aElement->GetScriptDeferred(),
+ aElement->GetScriptAsync());
+ } else {
+ // No usable preload found.
SRIMetadata sriMetadata;
{
@@ -1318,13 +1336,14 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
}
}
- request = CreateLoadRequest(scriptKind, aElement, version, ourCORSMode,
- sriMetadata);
- request->mURI = scriptURI;
+ request = CreateLoadRequest(scriptKind, scriptURI, aElement,
+ version, ourCORSMode, sriMetadata,
+ ourRefPolicy);
request->mIsInline = false;
- request->mReferrerPolicy = ourRefPolicy;
+ request->SetScriptMode(aElement->GetScriptDeferred(),
+ aElement->GetScriptAsync());
- // set aScriptFromHead to false so we don't treat non preloaded scripts as
+ // Set aScriptFromHead to false so we don't treat non-preloaded scripts as
// blockers for full page load. See bug 792438.
rv = StartLoad(request, type, false);
if (NS_FAILED(rv)) {
@@ -1342,18 +1361,15 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
request->mJSVersion = version;
- if (aElement->GetScriptAsync()) {
- request->mIsAsync = true;
+ if (request->IsAsyncScript()) {
+ AddAsyncRequest(request);
if (request->IsReadyToRun()) {
- mLoadedAsyncRequests.AppendElement(request);
// The script is available already. Run it ASAP when the event
// loop gets a chance to spin.
// KVKV TODO: Instead of processing immediately, try off-thread-parsing
// it and only schedule a pending ProcessRequest if that fails.
ProcessPendingRequestsAsync();
- } else {
- mLoadingAsyncRequests.AppendElement(request);
}
return false;
}
@@ -1372,7 +1388,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
}
// we now have a parser-inserted request that may or may not be still
// loading
- if (aElement->GetScriptDeferred() || request->IsModuleRequest()) {
+ if (request->IsDeferredScript()) {
// We don't want to run this yet.
// If we come here, the script is a parser-created script and it has
// the defer attribute but not the async attribute. Since a
@@ -1440,31 +1456,36 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
return false;
}
- // Inline scripts ignore ther CORS mode and are always CORS_NONE
- request = CreateLoadRequest(scriptKind, aElement, version, CORS_NONE,
- SRIMetadata()); // SRI doesn't apply
+ // Inline scripts ignore their CORS mode and are always CORS_NONE.
+ request = CreateLoadRequest(scriptKind, mDocument->GetDocumentURI(), aElement,
+ version, CORS_NONE,
+ SRIMetadata(), // SRI doesn't apply
+ ourRefPolicy);
request->mJSVersion = version;
request->mIsInline = true;
- request->mURI = mDocument->GetDocumentURI();
request->mLineNo = aElement->GetScriptLineNumber();
+ // Only the 'async' attribute is heeded on an inline module script and
+ // inline classic scripts ignore both these attributes.
+ MOZ_ASSERT(!aElement->GetScriptDeferred());
+ MOZ_ASSERT_IF(!request->IsModuleRequest(), !aElement->GetScriptAsync());
+ request->SetScriptMode(false, aElement->GetScriptAsync());
+
if (request->IsModuleRequest()) {
ModuleLoadRequest* modReq = request->AsModuleRequest();
modReq->mBaseURL = mDocument->GetDocBaseURI();
- rv = CreateModuleScript(modReq);
- MOZ_ASSERT(NS_FAILED(rv) == !modReq->mModuleScript);
- if (NS_FAILED(rv)) {
- modReq->LoadFailed();
- return false;
- }
+
if (aElement->GetScriptAsync()) {
- mLoadingAsyncRequests.AppendElement(request);
+ AddAsyncRequest(modReq);
} else {
- AddDeferRequest(request);
+ AddDeferRequest(modReq);
}
- if (!modReq->mModuleScript->IsErrored()) {
- StartFetchingModuleDependencies(modReq);
+
+ nsresult rv = ProcessFetchedModuleSource(modReq);
+ if (NS_FAILED(rv)) {
+ HandleLoadError(modReq, rv);
}
+
return false;
}
request->mProgress = ScriptLoadRequest::Progress::Ready;
@@ -1943,8 +1964,6 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
context->SetProcessingScriptTag(true);
nsresult rv;
{
- // Update our current script.
- AutoCurrentScriptUpdater scriptUpdater(this, aRequest->mElement);
Maybe<AutoCurrentScriptUpdater> masterScriptUpdater;
nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
if (master != mDocument) {
@@ -1958,17 +1977,19 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
}
if (aRequest->IsModuleRequest()) {
- rv = EnsureModuleResolveHook(cx);
- NS_ENSURE_SUCCESS(rv, rv);
+ // For modules, currentScript is set to null.
+ AutoCurrentScriptUpdater scriptUpdater(this, nullptr);
+
+ EnsureModuleResolveHook(cx);
ModuleLoadRequest* request = aRequest->AsModuleRequest();
MOZ_ASSERT(request->mModuleScript);
MOZ_ASSERT(!request->mOffThreadToken);
ModuleScript* moduleScript = request->mModuleScript;
- if (moduleScript->IsErrored()) {
- // Module has an error status
- JS::Rooted<JS::Value> error(cx, moduleScript->Error());
+ if (moduleScript->HasErrorToRethrow()) {
+ // Module has an error status to be rethrown
+ JS::Rooted<JS::Value> error(cx, moduleScript->ErrorToRethrow());
JS_SetPendingException(cx, error);
return NS_OK; // An error is reported by AutoEntryScript.
}
@@ -1983,6 +2004,9 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
rv = NS_OK; // An error is reported by AutoEntryScript.
}
} else {
+ // Update our current script.
+ AutoCurrentScriptUpdater scriptUpdater(this, aRequest->mElement);
+
JS::CompileOptions options(cx);
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
@@ -2236,19 +2260,41 @@ ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
nsresult aChannelStatus,
nsresult aSRIStatus,
mozilla::Vector<char16_t> &aString,
- mozilla::dom::SRICheckDataVerifier* aSRIDataVerifier)
+ SRICheckDataVerifier* aSRIDataVerifier)
{
ScriptLoadRequest* request = static_cast<ScriptLoadRequest*>(aContext);
NS_ASSERTION(request, "null request in stream complete handler");
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
+ nsresult rv = VerifySRI(request, aLoader, aSRIStatus, aSRIDataVerifier);
+
+ if (NS_SUCCEEDED(rv)) {
+ rv = PrepareLoadedRequest(request, aLoader, aChannelStatus, aString);
+ }
+
+ if (NS_FAILED(rv)) {
+ HandleLoadError(request, rv);
+ }
+
+ // Process our request and/or any pending ones
+ ProcessPendingRequests();
+
+ return NS_OK;
+}
+
+nsresult
+ScriptLoader::VerifySRI(ScriptLoadRequest* aRequest,
+ nsIIncrementalStreamLoader* aLoader,
+ nsresult aSRIStatus,
+ SRICheckDataVerifier* aSRIDataVerifier) const
+{
nsCOMPtr<nsIRequest> channelRequest;
aLoader->GetRequest(getter_AddRefs(channelRequest));
nsCOMPtr<nsIChannel> channel;
channel = do_QueryInterface(channelRequest);
nsresult rv = NS_OK;
- if (!request->mIntegrity.IsEmpty() &&
+ if (!aRequest->mIntegrity.IsEmpty() &&
NS_SUCCEEDED((rv = aSRIStatus))) {
MOZ_ASSERT(aSRIDataVerifier);
MOZ_ASSERT(mReporter);
@@ -2257,7 +2303,7 @@ ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
if (mDocument && mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
- rv = aSRIDataVerifier->Verify(request->mIntegrity, channel, sourceUri,
+ rv = aSRIDataVerifier->Verify(aRequest->mIntegrity, channel, sourceUri,
mReporter);
mReporter->FlushConsoleReports(mDocument);
if (NS_FAILED(rv)) {
@@ -2273,7 +2319,7 @@ ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
nsAutoCString violationURISpec;
mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec);
- uint32_t lineNo = request->mElement ? request->mElement->GetScriptLineNumber() : 0;
+ uint32_t lineNo = aRequest->mElement ? aRequest->mElement->GetScriptLineNumber() : 0;
csp->LogViolationDetails(
nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
NS_ConvertUTF8toUTF16(violationURISpec),
@@ -2281,78 +2327,79 @@ ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
rv = NS_ERROR_SRI_CORRUPT;
}
}
+
+ return rv;
+}
- if (NS_SUCCEEDED(rv)) {
- rv = PrepareLoadedRequest(request, aLoader, aChannelStatus, aString);
+void
+ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
+ /*
+ * Handle script not loading error because source was a tracking URL.
+ * We make a note of this script node by including it in a dedicated
+ * array of blocked tracking nodes under its parent document.
+ */
+ if (aResult == NS_ERROR_TRACKING_URI) {
+ nsCOMPtr<nsIContent> cont = do_QueryInterface(aRequest->mElement);
+ mDocument->AddBlockedTrackingNode(cont);
}
- if (NS_FAILED(rv)) {
- /*
- * Handle script not loading error because source was a tracking URL.
- * We make a note of this script node by including it in a dedicated
- * array of blocked tracking nodes under its parent document.
- */
- if (rv == NS_ERROR_TRACKING_URI) {
- nsCOMPtr<nsIContent> cont = do_QueryInterface(request->mElement);
- mDocument->AddBlockedTrackingNode(cont);
- }
-
- if (request->mIsDefer) {
- MOZ_ASSERT_IF(request->IsModuleRequest(),
- request->AsModuleRequest()->IsTopLevel());
- if (request->isInList()) {
- RefPtr<ScriptLoadRequest> req = mDeferRequests.Steal(request);
- FireScriptAvailable(rv, req);
- }
- } else if (request->mIsAsync) {
- MOZ_ASSERT_IF(request->IsModuleRequest(),
- request->AsModuleRequest()->IsTopLevel());
- if (request->isInList()) {
- RefPtr<ScriptLoadRequest> req = mLoadingAsyncRequests.Steal(request);
- FireScriptAvailable(rv, req);
- }
- } else if (request->mIsNonAsyncScriptInserted) {
- if (request->isInList()) {
- RefPtr<ScriptLoadRequest> req =
- mNonAsyncExternalScriptInsertedRequests.Steal(request);
- FireScriptAvailable(rv, req);
- }
- } else if (request->mIsXSLT) {
- if (request->isInList()) {
- RefPtr<ScriptLoadRequest> req = mXSLTRequests.Steal(request);
- FireScriptAvailable(rv, req);
- }
- } else if (request->IsModuleRequest()) {
- ModuleLoadRequest* modReq = request->AsModuleRequest();
- MOZ_ASSERT(!modReq->IsTopLevel());
- MOZ_ASSERT(!modReq->isInList());
- modReq->Cancel();
- FireScriptAvailable(rv, request);
- } else if (mParserBlockingRequest == request) {
- MOZ_ASSERT(!request->isInList());
- mParserBlockingRequest = nullptr;
- UnblockParser(request);
-
- // Ensure that we treat request->mElement as our current parser-inserted
- // script while firing onerror on it.
- MOZ_ASSERT(request->mElement->GetParserCreated());
- nsCOMPtr<nsIScriptElement> oldParserInsertedScript =
- mCurrentParserInsertedScript;
- mCurrentParserInsertedScript = request->mElement;
- FireScriptAvailable(rv, request);
- ContinueParserAsync(request);
- mCurrentParserInsertedScript = oldParserInsertedScript;
- } else {
- mPreloads.RemoveElement(request, PreloadRequestComparator());
- }
+ if (aRequest->IsModuleRequest() && !aRequest->mIsInline) {
+ auto request = aRequest->AsModuleRequest();
+ SetModuleFetchFinishedAndResumeWaitingRequests(request, aResult);
}
- // Process our request and/or any pending ones
- ProcessPendingRequests();
+ if (aRequest->mInDeferList) {
+ MOZ_ASSERT_IF(aRequest->IsModuleRequest(),
+ aRequest->AsModuleRequest()->IsTopLevel());
+ if (aRequest->isInList()) {
+ RefPtr<ScriptLoadRequest> req = mDeferRequests.Steal(aRequest);
+ FireScriptAvailable(aResult, req);
+ }
+ } else if (aRequest->mInAsyncList) {
+ MOZ_ASSERT_IF(aRequest->IsModuleRequest(),
+ aRequest->AsModuleRequest()->IsTopLevel());
+ if (aRequest->isInList()) {
+ RefPtr<ScriptLoadRequest> req = mLoadingAsyncRequests.Steal(aRequest);
+ FireScriptAvailable(aResult, req);
+ }
+ } else if (aRequest->mIsNonAsyncScriptInserted) {
+ if (aRequest->isInList()) {
+ RefPtr<ScriptLoadRequest> req =
+ mNonAsyncExternalScriptInsertedRequests.Steal(aRequest);
+ FireScriptAvailable(aResult, req);
+ }
+ } else if (aRequest->mIsXSLT) {
+ if (aRequest->isInList()) {
+ RefPtr<ScriptLoadRequest> req = mXSLTRequests.Steal(aRequest);
+ FireScriptAvailable(aResult, req);
+ }
+ } else if (aRequest->IsModuleRequest()) {
+ ModuleLoadRequest* modReq = aRequest->AsModuleRequest();
+ MOZ_ASSERT(!modReq->IsTopLevel());
+ MOZ_ASSERT(!modReq->isInList());
+ modReq->Cancel();
+ // A single error is fired for the top level module, so don't use
+ // FireScriptAvailable here.
+ } else if (mParserBlockingRequest == aRequest) {
+ MOZ_ASSERT(!aRequest->isInList());
+ mParserBlockingRequest = nullptr;
+ UnblockParser(aRequest);
- return NS_OK;
+ // Ensure that we treat request->mElement as our current parser-inserted
+ // script while firing onerror on it.
+ MOZ_ASSERT(aRequest->mElement->GetParserCreated());
+ nsCOMPtr<nsIScriptElement> oldParserInsertedScript =
+ mCurrentParserInsertedScript;
+ mCurrentParserInsertedScript = aRequest->mElement;
+ FireScriptAvailable(aResult, aRequest);
+ ContinueParserAsync(aRequest);
+ mCurrentParserInsertedScript = oldParserInsertedScript;
+ } else {
+ mPreloads.RemoveElement(aRequest, PreloadRequestComparator());
+ }
}
+
void
ScriptLoader::UnblockParser(ScriptLoadRequest* aParserBlockingRequest)
{
@@ -2377,23 +2424,6 @@ ScriptLoader::NumberOfProcessors()
return mNumberOfProcessors;
}
-void
-ScriptLoader::MaybeMoveToLoadedList(ScriptLoadRequest* aRequest)
-{
- MOZ_ASSERT(aRequest->IsReadyToRun());
-
- // If it's async, move it to the loaded list. aRequest->mIsAsync really
- // _should_ be in a list, but the consequences if it's not are bad enough we
- // want to avoid trying to move it if it's not.
- if (aRequest->mIsAsync) {
- MOZ_ASSERT(aRequest->isInList());
- if (aRequest->isInList()) {
- RefPtr<ScriptLoadRequest> req = mLoadingAsyncRequests.Steal(aRequest);
- mLoadedAsyncRequests.AppendElement(req);
- }
- }
-}
-
nsresult
ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
nsIIncrementalStreamLoader* aLoader,
@@ -2440,10 +2470,10 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
- // 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
- if (aRequest->mCORSMode == CORS_NONE) {
+ // 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. Module loads always use CORS.
+ if (!aRequest->IsModuleRequest() && aRequest->mCORSMode == CORS_NONE) {
rv = nsContentUtils::GetSecurityManager()->
GetChannelResultPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
@@ -2551,6 +2581,8 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
const nsAString &aCrossOrigin,
const nsAString& aIntegrity,
bool aScriptFromHead,
+ bool aAsync,
+ bool aDefer,
const mozilla::net::ReferrerPolicy aReferrerPolicy)
{
NS_ENSURE_TRUE_VOID(mDocument);
@@ -2560,7 +2592,7 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
}
// TODO: Preload module scripts.
- if (ModuleScriptsEnabled() && aType.LowerCaseEqualsASCII("module")) {
+ if (mDocument->ModuleScriptsEnabled() && aType.LowerCaseEqualsASCII("module")) {
return;
}
@@ -2577,11 +2609,11 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
}
RefPtr<ScriptLoadRequest> request =
- CreateLoadRequest(ScriptKind::Classic, nullptr, 0,
- Element::StringToCORSMode(aCrossOrigin), sriMetadata);
- request->mURI = aURI;
+ CreateLoadRequest(ScriptKind::Classic, aURI, nullptr, 0,
+ Element::StringToCORSMode(aCrossOrigin), sriMetadata,
+ aReferrerPolicy);
request->mIsInline = false;
- request->mReferrerPolicy = aReferrerPolicy;
+ request->SetScriptMode(aDefer, aAsync);
nsresult rv = StartLoad(request, aType, aScriptFromHead);
if (NS_FAILED(rv)) {
@@ -2596,7 +2628,10 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
void
ScriptLoader::AddDeferRequest(ScriptLoadRequest* aRequest)
{
- aRequest->mIsDefer = true;
+ MOZ_ASSERT(aRequest->IsDeferredScript());
+ MOZ_ASSERT(!aRequest->mInDeferList && !aRequest->mInAsyncList);
+
+ aRequest->mInDeferList = true;
mDeferRequests.AppendElement(aRequest);
if (mDeferEnabled && aRequest == mDeferRequests.getFirst() &&
mDocument && !mBlockingDOMContentLoaded) {
@@ -2606,6 +2641,37 @@ ScriptLoader::AddDeferRequest(ScriptLoadRequest* aRequest)
}
}
+void
+ScriptLoader::AddAsyncRequest(ScriptLoadRequest* aRequest)
+{
+ MOZ_ASSERT(aRequest->IsAsyncScript());
+ MOZ_ASSERT(!aRequest->mInDeferList && !aRequest->mInAsyncList);
+
+ aRequest->mInAsyncList = true;
+ if (aRequest->IsReadyToRun()) {
+ mLoadedAsyncRequests.AppendElement(aRequest);
+ } else {
+ mLoadingAsyncRequests.AppendElement(aRequest);
+ }
+}
+
+void
+ScriptLoader::MaybeMoveToLoadedList(ScriptLoadRequest* aRequest)
+{
+ MOZ_ASSERT(aRequest->IsReadyToRun());
+
+ // If it's async, move it to the loaded list. aRequest->mInAsyncList really
+ // _should_ be in a list, but the consequences if it's not are bad enough we
+ // want to avoid trying to move it if it's not.
+ if (aRequest->mInAsyncList) {
+ MOZ_ASSERT(aRequest->isInList());
+ if (aRequest->isInList()) {
+ RefPtr<ScriptLoadRequest> req = mLoadingAsyncRequests.Steal(aRequest);
+ mLoadedAsyncRequests.AppendElement(req);
+ }
+ }
+}
+
bool
ScriptLoader::MaybeRemovedDeferRequests()
{
diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h
index e6b75bf3b..ed1e6acbc 100644
--- a/dom/script/ScriptLoader.h
+++ b/dom/script/ScriptLoader.h
@@ -62,17 +62,21 @@ protected:
public:
ScriptLoadRequest(ScriptKind aKind,
+ nsIURI* aURI,
nsIScriptElement* aElement,
uint32_t aVersion,
mozilla::CORSMode aCORSMode,
- const mozilla::dom::SRIMetadata &aIntegrity)
+ const SRIMetadata& aIntegrity,
+ nsIURI* aReferrer,
+ mozilla::net::ReferrerPolicy aReferrerPolicy)
: mKind(aKind),
mElement(aElement),
mProgress(Progress::Loading),
+ mScriptMode(ScriptMode::eBlocking),
mIsInline(true),
mHasSourceMapURL(false),
- mIsDefer(false),
- mIsAsync(false),
+ mInDeferList(false),
+ mInAsyncList(false),
mIsNonAsyncScriptInserted(false),
mIsXSLT(false),
mIsCanceled(false),
@@ -81,10 +85,12 @@ public:
mScriptTextBuf(nullptr),
mScriptTextLength(0),
mJSVersion(aVersion),
+ mURI(aURI),
mLineNo(1),
mCORSMode(aCORSMode),
mIntegrity(aIntegrity),
- mReferrerPolicy(mozilla::net::RP_Default)
+ mReferrer(aReferrer),
+ mReferrerPolicy(aReferrerPolicy)
{
}
@@ -100,7 +106,8 @@ public:
void FireScriptAvailable(nsresult aResult)
{
- mElement->ScriptAvailable(aResult, mElement, mIsInline, mURI, mLineNo);
+ bool isInlineClassicScript = mIsInline && !IsModuleRequest();
+ mElement->ScriptAvailable(aResult, mElement, isInlineClassicScript, mURI, mLineNo);
}
void FireScriptEvaluated(nsresult aResult)
{
@@ -143,6 +150,29 @@ public:
(IsReadyToRun() && mWasCompiledOMT);
}
+ enum class ScriptMode : uint8_t {
+ eBlocking,
+ eDeferred,
+ eAsync
+ };
+
+ void SetScriptMode(bool aDeferAttr, bool aAsyncAttr);
+
+ bool IsBlockingScript() const
+ {
+ return mScriptMode == ScriptMode::eBlocking;
+ }
+
+ bool IsDeferredScript() const
+ {
+ return mScriptMode == ScriptMode::eDeferred;
+ }
+
+ bool IsAsyncScript() const
+ {
+ return mScriptMode == ScriptMode::eAsync;
+ }
+
void MaybeCancelOffThreadScript();
using super::getNext;
@@ -151,10 +181,11 @@ public:
const ScriptKind mKind;
nsCOMPtr<nsIScriptElement> mElement;
Progress mProgress; // Are we still waiting for a load to complete?
+ ScriptMode mScriptMode; // Whether this script is blocking, deferred or async.
bool mIsInline; // Is the script inline or loaded?
bool mHasSourceMapURL; // Does the HTTP header have a source map url?
- bool mIsDefer; // True if we live in mDeferRequests.
- bool mIsAsync; // True if we live in mLoadingAsyncRequests or mLoadedAsyncRequests.
+ bool mInDeferList; // True if we live in mDeferRequests.
+ bool mInAsyncList; // True if we live in mLoadingAsyncRequests or mLoadedAsyncRequests.
bool mIsNonAsyncScriptInserted; // True if we live in mNonAsyncExternalScriptInsertedRequests
bool mIsXSLT; // True if we live in mXSLTRequests.
bool mIsCanceled; // True if we have been explicitly canceled.
@@ -164,13 +195,14 @@ public:
char16_t* mScriptTextBuf; // Holds script text for non-inline scripts. Don't
size_t mScriptTextLength; // use nsString so we can give ownership to jsapi.
uint32_t mJSVersion;
- nsCOMPtr<nsIURI> mURI;
+ const nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mOriginPrincipal;
nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing.
int32_t mLineNo;
const mozilla::CORSMode mCORSMode;
- const mozilla::dom::SRIMetadata mIntegrity;
- mozilla::net::ReferrerPolicy mReferrerPolicy;
+ const SRIMetadata mIntegrity;
+ const nsCOMPtr<nsIURI> mReferrer;
+ const mozilla::net::ReferrerPolicy mReferrerPolicy;
};
class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest>
@@ -452,6 +484,8 @@ public:
const nsAString &aCrossOrigin,
const nsAString& aIntegrity,
bool aScriptFromHead,
+ bool aAsync,
+ bool aDefer,
const mozilla::net::ReferrerPolicy aReferrerPolicy);
/**
@@ -467,12 +501,13 @@ public:
private:
virtual ~ScriptLoader();
- ScriptLoadRequest* CreateLoadRequest(
- ScriptKind aKind,
- nsIScriptElement* aElement,
- uint32_t aVersion,
- mozilla::CORSMode aCORSMode,
- const mozilla::dom::SRIMetadata &aIntegrity);
+ ScriptLoadRequest* CreateLoadRequest(ScriptKind aKind,
+ nsIURI* aURI,
+ nsIScriptElement* aElement,
+ uint32_t aVersion,
+ mozilla::CORSMode aCORSMode,
+ const SRIMetadata& aIntegrity,
+ mozilla::net::ReferrerPolicy aReferrerPolicy);
/**
* Unblocks the creator parser of the parser-blocking scripts.
@@ -500,6 +535,8 @@ private:
nsresult StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
bool aScriptFromHead);
+ void HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult);
+
/**
* Process any pending requests asynchronously (i.e. off an event) if there
* are any. Note that this is a no-op if there aren't any currently pending
@@ -534,6 +571,11 @@ private:
return mEnabled && !mBlockerCount;
}
+ nsresult VerifySRI(ScriptLoadRequest *aRequest,
+ nsIIncrementalStreamLoader* aLoader,
+ nsresult aSRIStatus,
+ SRICheckDataVerifier* aSRIDataVerifier) const;
+
nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest);
nsresult ProcessRequest(ScriptLoadRequest* aRequest);
nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest);
@@ -556,6 +598,7 @@ private:
mozilla::Vector<char16_t> &aString);
void AddDeferRequest(ScriptLoadRequest* aRequest);
+ void AddAsyncRequest(ScriptLoadRequest* aRequest);
bool MaybeRemovedDeferRequests();
void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
@@ -563,30 +606,30 @@ private:
JS::SourceBufferHolder GetScriptSource(ScriptLoadRequest* aRequest,
nsAutoString& inlineData);
- bool ModuleScriptsEnabled();
-
void SetModuleFetchStarted(ModuleLoadRequest *aRequest);
void SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest,
nsresult aResult);
bool IsFetchingModule(ModuleLoadRequest *aRequest) const;
- bool ModuleMapContainsModule(ModuleLoadRequest *aRequest) const;
- RefPtr<mozilla::GenericPromise> WaitForModuleFetch(ModuleLoadRequest *aRequest);
+ bool ModuleMapContainsURL(nsIURI* aURL) const;
+ RefPtr<mozilla::GenericPromise> WaitForModuleFetch(nsIURI* aURL);
ModuleScript* GetFetchedModule(nsIURI* aURL) const;
- friend bool
- HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp);
+ friend JSObject*
+ HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
+ JS::Handle<JSString*> aSpecifier);
nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);
void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest);
void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
+ JS::Value FindFirstParseError(ModuleLoadRequest* aRequest);
bool InstantiateModuleTree(ModuleLoadRequest* aRequest);
void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
RefPtr<mozilla::GenericPromise>
- StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest, nsIURI* aURI);
+ StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent, nsIURI* aURI);
nsIDocument* mDocument; // [WEAK]
nsCOMArray<nsIScriptLoaderObserver> mObservers;
diff --git a/dom/script/nsIScriptElement.h b/dom/script/nsIScriptElement.h
index 470d51c94..e3e1bc49a 100644
--- a/dom/script/nsIScriptElement.h
+++ b/dom/script/nsIScriptElement.h
@@ -13,6 +13,7 @@
#include "nsIScriptLoaderObserver.h"
#include "nsWeakPtr.h"
#include "nsIParser.h"
+#include "nsIDocument.h"
#include "nsContentCreatorFunctions.h"
#include "nsIDOMHTMLScriptElement.h"
#include "mozilla/CORSMode.h"
@@ -37,6 +38,7 @@ public:
mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
mFrozen(false),
+ mIsModule(false),
mDefer(false),
mAsync(false),
mExternal(false),
@@ -73,11 +75,25 @@ public:
virtual void GetScriptCharset(nsAString& charset) = 0;
/**
- * Freezes the return values of GetScriptDeferred(), GetScriptAsync() and
- * GetScriptURI() so that subsequent modifications to the attributes don't
- * change execution behavior.
+ * Freezes the return values of the following methods so that subsequent
+ * modifications to the attributes don't change execution behavior:
+ * - GetScriptIsModule()
+ * - GetScriptDeferred()
+ * - GetScriptAsync()
+ * - GetScriptURI()
+ * - GetScriptExternal()
*/
- virtual void FreezeUriAsyncDefer() = 0;
+ virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) = 0;
+
+ /**
+ * Is the script a module script?
+ * Currently only supported by HTML scripts.
+ */
+ bool GetScriptIsModule()
+ {
+ NS_PRECONDITION(mFrozen, "Execution attributes not yet frozen: Not ready for this call!");
+ return mIsModule;
+ }
/**
* Is the script deferred. Currently only supported by HTML scripts.
@@ -293,6 +309,11 @@ protected:
bool mFrozen;
/**
+ * The effective moduleness.
+ */
+ bool mIsModule;
+
+ /**
* The effective deferredness.
*/
bool mDefer;
diff --git a/dom/script/nsIScriptLoaderObserver.idl b/dom/script/nsIScriptLoaderObserver.idl
index ed7196525..880738360 100644
--- a/dom/script/nsIScriptLoaderObserver.idl
+++ b/dom/script/nsIScriptLoaderObserver.idl
@@ -20,15 +20,16 @@ interface nsIScriptLoaderObserver : nsISupports {
* a script. If this is a failure code, script evaluation
* will not occur.
* @param aElement The element being processed.
- * @param aIsInline Is this an inline script or externally loaded?
+ * @param aIsInline Is this an inline classic script (as opposed to an
+ * externally loaded classic script or module script)?
* @param aURI What is the URI of the script (the document URI if
* it is inline).
* @param aLineNo At what line does the script appear (generally 1
* if it is a loaded script).
*/
- void scriptAvailable(in nsresult aResult,
+ void scriptAvailable(in nsresult aResult,
in nsIScriptElement aElement,
- in boolean aIsInline,
+ in boolean aIsInlineClassicScript,
in nsIURI aURI,
in int32_t aLineNo);
@@ -40,7 +41,7 @@ interface nsIScriptLoaderObserver : nsISupports {
* @param aElement The element being processed.
* @param aIsInline Is this an inline script or externally loaded?
*/
- void scriptEvaluated(in nsresult aResult,
+ void scriptEvaluated(in nsresult aResult,
in nsIScriptElement aElement,
in boolean aIsInline);