Bug 1342416 - Preload module scripts r=baku

This commit is contained in:
Jon Coppeard
2018-02-15 13:18:59 +00:00
parent b13ee8ea44
commit d8400cb4bd
8 changed files with 130 additions and 32 deletions

View File

@@ -511,6 +511,7 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
}
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL);
aRequest->mModuleScript = moduleScript;
@@ -999,7 +1000,7 @@ ScriptLoader::StartLoad(ScriptLoadRequest* aRequest)
if (aRequest->IsModuleRequest()) {
// Check whether the module has been fetched or is currently being fetched,
// and if so wait for it.
// and if so wait for it rather than starting a new fetch.
ModuleLoadRequest* request = aRequest->AsModuleRequest();
if (ModuleMapContainsURL(request->mURI)) {
LOG(("ScriptLoadRequest (%p): Waiting for module fetch", aRequest));
@@ -1009,10 +1010,6 @@ ScriptLoader::StartLoad(ScriptLoadRequest* aRequest)
&ModuleLoadRequest::LoadFailed);
return NS_OK;
}
// Otherwise put the URL in the module map and mark it as fetching.
SetModuleFetchStarted(request);
LOG(("ScriptLoadRequest (%p): Start fetching module", aRequest));
}
nsContentPolicyType contentPolicyType = aRequest->IsPreload()
@@ -1175,7 +1172,17 @@ ScriptLoader::StartLoad(ScriptLoadRequest* aRequest)
rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), handler);
NS_ENSURE_SUCCESS(rv, rv);
return channel->AsyncOpen2(loader);
rv = channel->AsyncOpen2(loader);
NS_ENSURE_SUCCESS(rv, rv);
if (aRequest->IsModuleRequest()) {
// We successfully started fetching a module so put its URL in the module
// map and mark it as fetching.
SetModuleFetchStarted(aRequest->AsModuleRequest());
LOG(("ScriptLoadRequest (%p): Start fetching module", aRequest));
}
return NS_OK;
}
bool
@@ -1226,12 +1233,8 @@ ScriptLoader::CreateLoadRequest(ScriptKind aKind,
nsIURI* referrer = mDocument->GetDocumentURI();
if (aKind == ScriptKind::eClassic) {
ScriptLoadRequest* slr = new ScriptLoadRequest(aKind, aURI, aElement,
aCORSMode, aIntegrity,
referrer, aReferrerPolicy);
LOG(("ScriptLoader %p creates ScriptLoadRequest %p", this, slr));
return slr;
return new ScriptLoadRequest(aKind, aURI, aElement, aCORSMode, aIntegrity,
referrer, aReferrerPolicy);
}
MOZ_ASSERT(aKind == ScriptKind::eModule);
@@ -1313,6 +1316,9 @@ ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
nsAutoString aTypeAttr,
nsIContent* aScriptContent)
{
LOG(("ScriptLoader (%p): Process external script for element %p",
this, aElement));
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
if (!scriptURI) {
// Asynchronously report the failure to create a URI object
@@ -1327,6 +1333,8 @@ ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
if (request && NS_FAILED(CheckContentPolicy(mDocument, aElement, request->mURI,
aTypeAttr, false))) {
LOG(("ScriptLoader (%p): content policy check failed for preload", this));
// Probably plans have changed; even though the preload was allowed seems
// like the actual load is not; let's cancel the preload request.
request->Cancel();
@@ -1337,6 +1345,8 @@ ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
if (request) {
// Use the preload request.
LOG(("ScriptLoadRequest (%p): Using preload request", request.get()));
// It's possible these attributes changed since we started the preload so
// update them here.
request->SetScriptMode(aElement->GetScriptDeferred(),
@@ -1371,6 +1381,9 @@ ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
// keep request->mScriptFromHead to false so we don't treat non preloaded
// scripts as blockers for full page load. See bug 792438.
LOG(("ScriptLoadRequest (%p): Created request for external script",
request.get()));
nsresult rv = StartLoad(request);
if (NS_FAILED(rv)) {
ReportErrorToConsole(request, rv);
@@ -1389,8 +1402,9 @@ ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
}
}
// Should still be in loading stage of script.
NS_ASSERTION(!request->InCompilingStage(),
// We should still be in loading stage of script unless we're loading a
// module.
NS_ASSERTION(!request->InCompilingStage() || request->IsModuleRequest(),
"Request should not yet be in compiling stage.");
if (request->IsAsyncScript()) {
@@ -1581,6 +1595,8 @@ ScriptLoadRequest*
ScriptLoader::LookupPreloadRequest(nsIScriptElement* aElement,
ScriptKind aScriptKind)
{
MOZ_ASSERT(aElement);
nsTArray<PreloadInfo>::index_type i =
mPreloads.IndexOf(aElement->GetScriptURI(), 0, PreloadURIComparator());
if (i == nsTArray<PreloadInfo>::NoIndex) {
@@ -2058,14 +2074,16 @@ ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi,
aOptions->setMutedErrors(!subsumes);
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> elementVal(cx);
MOZ_ASSERT(aRequest->mElement);
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, aRequest->mElement,
&elementVal,
/* aAllowWrapping = */ true))) {
MOZ_ASSERT(elementVal.isObject());
aOptions->setElement(&elementVal.toObject());
if (!aRequest->IsModuleRequest()) {
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> elementVal(cx);
MOZ_ASSERT(aRequest->mElement);
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, aRequest->mElement,
&elementVal,
/* aAllowWrapping = */ true))) {
MOZ_ASSERT(elementVal.isObject());
aOptions->setElement(&elementVal.toObject());
}
}
return NS_OK;
@@ -2223,6 +2241,12 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
MOZ_ASSERT(module);
if (!moduleScript->SourceElementAssociated()) {
rv = nsJSUtils::InitModuleSourceElement(cx, module, aRequest->mElement);
NS_ENSURE_SUCCESS(rv, rv);
moduleScript->SetSourceElementAssociated();
}
rv = nsJSUtils::ModuleEvaluate(cx, module);
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
if (NS_FAILED(rv)) {
@@ -2958,7 +2982,7 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult)
RefPtr<ScriptLoadRequest> req = mXSLTRequests.Steal(aRequest);
FireScriptAvailable(aResult, req);
}
} else if (aRequest->IsModuleRequest()) {
} else if (aRequest->IsModuleRequest() && !aRequest->IsPreload()) {
ModuleLoadRequest* modReq = aRequest->AsModuleRequest();
MOZ_ASSERT(!modReq->IsTopLevel());
MOZ_ASSERT(!modReq->isInList());
@@ -2978,9 +3002,19 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult)
FireScriptAvailable(aResult, aRequest);
ContinueParserAsync(aRequest);
mCurrentParserInsertedScript = oldParserInsertedScript;
} else {
mPreloads.RemoveElement(aRequest, PreloadRequestComparator());
} else if (aRequest->IsPreload()) {
if (aRequest->IsModuleRequest()) {
aRequest->Cancel();
}
if (aRequest->IsTopLevel()) {
MOZ_ALWAYS_TRUE(mPreloads.RemoveElement(aRequest, PreloadRequestComparator()));
}
MOZ_ASSERT(!aRequest->isInList());
AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::LoadError);
} else {
// This happens for blocking requests cancelled by ParsingComplete().
MOZ_ASSERT(aRequest->IsCanceled());
MOZ_ASSERT(!aRequest->isInList());
}
}
@@ -3186,19 +3220,26 @@ ScriptLoader::PreloadURI(nsIURI* aURI,
return;
}
ScriptKind scriptKind = ScriptKind::eClassic;
if (mDocument->ModuleScriptsEnabled()) {
// Don't load nomodule scripts.
if (aNoModule) {
return;
}
// TODO: Preload module scripts.
if (aType.LowerCaseEqualsASCII("module")) {
return;
static const char kASCIIWhitespace[] = "\t\n\f\r ";
nsAutoString type(aType);
type.Trim(kASCIIWhitespace);
if (type.LowerCaseEqualsASCII("module")) {
scriptKind = ScriptKind::eModule;
}
}
if (!aType.IsEmpty() && !nsContentUtils::IsJavascriptMIMEType(aType)) {
if (scriptKind == ScriptKind::eClassic &&
!aType.IsEmpty() && !nsContentUtils::IsJavascriptMIMEType(aType))
{
// Unknown type. Don't load it.
return;
}
@@ -3207,7 +3248,7 @@ ScriptLoader::PreloadURI(nsIURI* aURI,
GetSRIMetadata(aIntegrity, &sriMetadata);
RefPtr<ScriptLoadRequest> request =
CreateLoadRequest(ScriptKind::eClassic, aURI, nullptr,
CreateLoadRequest(scriptKind, aURI, nullptr,
Element::StringToCORSMode(aCrossOrigin), sriMetadata,
aReferrerPolicy);
request->mTriggeringPrincipal = mDocument->NodePrincipal();
@@ -3215,6 +3256,13 @@ ScriptLoader::PreloadURI(nsIURI* aURI,
request->mScriptFromHead = aScriptFromHead;
request->SetScriptMode(aDefer, aAsync);
if (LOG_ENABLED()) {
nsAutoCString url;
aURI->GetAsciiSpec(url);
LOG(("ScriptLoadRequest (%p): Created preload request for %s",
request.get(), url.get()));
}
nsresult rv = StartLoad(request);
if (NS_FAILED(rv)) {
return;