Backed out changeset ef258af45592 (bug 1429535) for test_bug704320_preload.html timeouts

This commit is contained in:
Jon Coppeard 2018-01-11 13:14:23 +00:00
parent 3f30371b5a
commit 2219c13082
2 changed files with 187 additions and 227 deletions

View File

@ -1286,180 +1286,199 @@ 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()) {
return ProcessExternalScript(aElement, scriptKind, type, scriptContent);
}
return ProcessInlineScript(aElement, scriptKind);
}
bool
ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
ScriptKind aScriptKind,
nsAutoString aTypeAttr,
nsIContent* aScriptContent)
{
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
if (!scriptURI) {
// Asynchronously report the failure to create a URI object
NS_DispatchToCurrentThread(
NewRunnableMethod("nsIScriptElement::FireErrorEvent",
aElement,
&nsIScriptElement::FireErrorEvent));
return false;
}
RefPtr<ScriptLoadRequest> request = LookupPreloadRequest(aElement, aScriptKind);
if (request && NS_FAILED(CheckContentPolicy(mDocument, aElement, request->mURI,
aTypeAttr, false))) {
// 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();
return false;
}
if (request) {
// Use the preload request.
request->mElement = aElement;
// 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;
{
nsAutoString integrity;
aScriptContent->AsElement()->GetAttr(kNameSpaceID_None,
nsGkAtoms::integrity,
integrity);
GetSRIMetadata(integrity, &sriMetadata);
}
nsCOMPtr<nsIPrincipal> principal = aElement->GetScriptURITriggeringPrincipal();
if (!principal) {
principal = aScriptContent->NodePrincipal();
}
CORSMode ourCORSMode = aElement->GetCORSMode();
mozilla::net::ReferrerPolicy ourRefPolicy = mDocument->GetReferrerPolicy();
request = CreateLoadRequest(aScriptKind, scriptURI, aElement,
ourCORSMode, sriMetadata, ourRefPolicy);
request->mTriggeringPrincipal = Move(principal);
request->mIsInline = false;
request->SetScriptMode(aElement->GetScriptDeferred(),
aElement->GetScriptAsync());
// keep request->mScriptFromHead to false so we don't treat non preloaded
// scripts as blockers for full page load. See bug 792438.
nsresult rv = StartLoad(request);
if (NS_FAILED(rv)) {
ReportErrorToConsole(request, rv);
// Asynchronously report the load failure
// external script
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
if (!scriptURI) {
// Asynchronously report the failure to create a URI object
NS_DispatchToCurrentThread(
NewRunnableMethod("nsIScriptElement::FireErrorEvent",
aElement,
&nsIScriptElement::FireErrorEvent));
return false;
}
}
// Should still be in loading stage of script.
NS_ASSERTION(!request->InCompilingStage(),
"Request should not yet be in compiling stage.");
// Double-check that the preload matches what we're asked to load now.
CORSMode ourCORSMode = aElement->GetCORSMode();
nsTArray<PreloadInfo>::index_type i =
mPreloads.IndexOf(scriptURI.get(), 0, PreloadURIComparator());
if (i != nsTArray<PreloadInfo>::NoIndex) {
// preloaded
// note that a script-inserted script can steal a preload!
request = mPreloads[i].mRequest;
request->mElement = aElement;
nsString preloadCharset(mPreloads[i].mCharset);
mPreloads.RemoveElementAt(i);
if (request->IsAsyncScript()) {
AddAsyncRequest(request);
if (request->IsReadyToRun()) {
// The script is available already. Run it ASAP when the event
// loop gets a chance to spin.
// Double-check that the charset the preload used is the same as
// the charset we have now.
nsAutoString elementCharset;
aElement->GetScriptCharset(elementCharset);
if (elementCharset.Equals(preloadCharset) &&
ourCORSMode == request->mCORSMode &&
ourRefPolicy == request->mReferrerPolicy &&
scriptKind == request->mKind) {
rv = CheckContentPolicy(mDocument, aElement, request->mURI, type, false);
if (NS_FAILED(rv)) {
// 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();
return false;
}
} else {
// Drop the preload
request = nullptr;
}
}
// KVKV TODO: Instead of processing immediately, try off-thread-parsing
// it and only schedule a pending ProcessRequest if that fails.
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;
{
nsAutoString integrity;
scriptContent->AsElement()->GetAttr(kNameSpaceID_None,
nsGkAtoms::integrity,
integrity);
if (!integrity.IsEmpty()) {
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
("ScriptLoader::ProcessScriptElement, integrity=%s",
NS_ConvertUTF16toUTF8(integrity).get()));
nsAutoCString sourceUri;
if (mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
SRICheck::IntegrityMetadata(integrity, sourceUri, mReporter,
&sriMetadata);
}
}
nsCOMPtr<nsIPrincipal> principal = aElement->GetScriptURITriggeringPrincipal();
if (!principal) {
principal = scriptContent->NodePrincipal();
}
request = CreateLoadRequest(scriptKind, scriptURI, aElement, ourCORSMode,
sriMetadata, ourRefPolicy);
request->mTriggeringPrincipal = Move(principal);
request->mIsInline = false;
request->SetScriptMode(aElement->GetScriptDeferred(),
aElement->GetScriptAsync());
// keep request->mScriptFromHead to false so we don't treat non preloaded
// scripts as blockers for full page load. See bug 792438.
rv = StartLoad(request);
if (NS_FAILED(rv)) {
ReportErrorToConsole(request, rv);
// Asynchronously report the load failure
NS_DispatchToCurrentThread(
NewRunnableMethod("nsIScriptElement::FireErrorEvent",
aElement,
&nsIScriptElement::FireErrorEvent));
return false;
}
}
// Should still be in loading stage of script.
NS_ASSERTION(!request->InCompilingStage(),
"Request should not yet be in compiling stage.");
if (request->IsAsyncScript()) {
AddAsyncRequest(request);
if (request->IsReadyToRun()) {
// 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();
}
return false;
}
if (!aElement->GetParserCreated()) {
// Violate the HTML5 spec in order to make LABjs and the "order" plug-in
// for RequireJS work with their Gecko-sniffed code path. See
// http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
request->mIsNonAsyncScriptInserted = true;
mNonAsyncExternalScriptInsertedRequests.AppendElement(request);
if (request->IsReadyToRun()) {
// The script is available already. Run it ASAP when the event
// loop gets a chance to spin.
ProcessPendingRequestsAsync();
}
return false;
}
// we now have a parser-inserted request that may or may not be still
// loading
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
// a parser-inserted script is being run, we came here by the parser
// running the script, which means the parser is still alive and the
// parse is ongoing.
NS_ASSERTION(mDocument->GetCurrentContentSink() ||
aElement->GetParserCreated() == FROM_PARSER_XSLT,
"Non-XSLT Defer script on a document without an active parser; bug 592366.");
AddDeferRequest(request);
return false;
}
if (aElement->GetParserCreated() == FROM_PARSER_XSLT) {
// Need to maintain order for XSLT-inserted scripts
NS_ASSERTION(!mParserBlockingRequest,
"Parser-blocking scripts and XSLT scripts in the same doc!");
request->mIsXSLT = true;
mXSLTRequests.AppendElement(request);
if (request->IsReadyToRun()) {
// The script is available already. Run it ASAP when the event
// loop gets a chance to spin.
ProcessPendingRequestsAsync();
}
return true;
}
if (request->IsReadyToRun() && ReadyToExecuteParserBlockingScripts()) {
// The request has already been loaded and there are no pending style
// sheets. If the script comes from the network stream, cheat for
// performance reasons and avoid a trip through the event loop.
if (aElement->GetParserCreated() == FROM_PARSER_NETWORK) {
return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
}
// Otherwise, we've got a document.written script, make a trip through
// the event loop to hide the preload effects from the scripts on the
// Web page.
NS_ASSERTION(!mParserBlockingRequest,
"There can be only one parser-blocking script at a time");
NS_ASSERTION(mXSLTRequests.isEmpty(),
"Parser-blocking scripts and XSLT scripts in the same doc!");
mParserBlockingRequest = request;
ProcessPendingRequestsAsync();
return true;
}
return false;
}
if (!aElement->GetParserCreated()) {
// Violate the HTML5 spec in order to make LABjs and the "order" plug-in
// for RequireJS work with their Gecko-sniffed code path. See
// http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
request->mIsNonAsyncScriptInserted = true;
mNonAsyncExternalScriptInsertedRequests.AppendElement(request);
if (request->IsReadyToRun()) {
// The script is available already. Run it ASAP when the event
// loop gets a chance to spin.
ProcessPendingRequestsAsync();
}
return false;
}
// we now have a parser-inserted request that may or may not be still
// loading
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
// a parser-inserted script is being run, we came here by the parser
// running the script, which means the parser is still alive and the
// parse is ongoing.
NS_ASSERTION(mDocument->GetCurrentContentSink() ||
aElement->GetParserCreated() == FROM_PARSER_XSLT,
"Non-XSLT Defer script on a document without an active parser; bug 592366.");
AddDeferRequest(request);
return false;
}
if (aElement->GetParserCreated() == FROM_PARSER_XSLT) {
// Need to maintain order for XSLT-inserted scripts
NS_ASSERTION(!mParserBlockingRequest,
"Parser-blocking scripts and XSLT scripts in the same doc!");
request->mIsXSLT = true;
mXSLTRequests.AppendElement(request);
if (request->IsReadyToRun()) {
// The script is available already. Run it ASAP when the event
// loop gets a chance to spin.
ProcessPendingRequestsAsync();
}
return true;
}
if (request->IsReadyToRun() && ReadyToExecuteParserBlockingScripts()) {
// The request has already been loaded and there are no pending style
// sheets. If the script comes from the network stream, cheat for
// performance reasons and avoid a trip through the event loop.
if (aElement->GetParserCreated() == FROM_PARSER_NETWORK) {
return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
}
// Otherwise, we've got a document.written script, make a trip through
// the event loop to hide the preload effects from the scripts on the
// Web page.
// The script hasn't loaded yet or there's a style sheet blocking it.
// The script will be run when it loads or the style sheet loads.
NS_ASSERTION(!mParserBlockingRequest,
"There can be only one parser-blocking script at a time");
NS_ASSERTION(mXSLTRequests.isEmpty(),
"Parser-blocking scripts and XSLT scripts in the same doc!");
mParserBlockingRequest = request;
ProcessPendingRequestsAsync();
return true;
}
// The script hasn't loaded yet or there's a style sheet blocking it.
// The script will be run when it loads or the style sheet loads.
NS_ASSERTION(!mParserBlockingRequest,
"There can be only one parser-blocking script at a time");
NS_ASSERTION(mXSLTRequests.isEmpty(),
"Parser-blocking scripts and XSLT scripts in the same doc!");
mParserBlockingRequest = request;
return true;
}
bool
ScriptLoader::ProcessInlineScript(nsIScriptElement* aElement,
ScriptKind aScriptKind)
{
// inline script
// Is this document sandboxed without 'allow-scripts'?
if (mDocument->HasScriptsBlockedBySandbox()) {
return false;
@ -1472,15 +1491,14 @@ ScriptLoader::ProcessInlineScript(nsIScriptElement* aElement,
// Inline classic scripts ignore their CORS mode and are always CORS_NONE.
CORSMode corsMode = CORS_NONE;
if (aScriptKind == ScriptKind::eModule) {
if (scriptKind == ScriptKind::eModule) {
corsMode = aElement->GetCORSMode();
}
RefPtr<ScriptLoadRequest> request =
CreateLoadRequest(aScriptKind, mDocument->GetDocumentURI(), aElement,
corsMode,
SRIMetadata(), // SRI doesn't apply
mDocument->GetReferrerPolicy());
request = CreateLoadRequest(scriptKind, mDocument->GetDocumentURI(), aElement,
corsMode,
SRIMetadata(), // SRI doesn't apply
ourRefPolicy);
request->mIsInline = true;
request->mTriggeringPrincipal = mDocument->NodePrincipal();
request->mLineNo = aElement->GetScriptLineNumber();
@ -1556,59 +1574,6 @@ ScriptLoader::ProcessInlineScript(nsIScriptElement* aElement,
return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
}
ScriptLoadRequest*
ScriptLoader::LookupPreloadRequest(nsIScriptElement* aElement,
ScriptKind aScriptKind)
{
nsTArray<PreloadInfo>::index_type i =
mPreloads.IndexOf(aElement->GetScriptURI(), 0, PreloadURIComparator());
if (i == nsTArray<PreloadInfo>::NoIndex) {
return nullptr;
}
// Found preloaded request. Note that a script-inserted script can steal a
// preload!
RefPtr<ScriptLoadRequest> request = mPreloads[i].mRequest;
nsString preloadCharset(mPreloads[i].mCharset);
mPreloads.RemoveElementAt(i);
// Double-check that the charset the preload used is the same as the charset
// we have now.
nsAutoString elementCharset;
aElement->GetScriptCharset(elementCharset);
if (!elementCharset.Equals(preloadCharset) ||
aElement->GetCORSMode() != request->mCORSMode ||
mDocument->GetReferrerPolicy() != request->mReferrerPolicy ||
aScriptKind != request->mKind) {
// Drop the preload.
return nullptr;
}
return request;
}
void
ScriptLoader::GetSRIMetadata(const nsAString& aIntegrityAttr,
SRIMetadata *aMetadataOut)
{
MOZ_ASSERT(aMetadataOut->IsEmpty());
if (aIntegrityAttr.IsEmpty()) {
return;
}
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
("ScriptLoader::GetSRIMetadata, integrity=%s",
NS_ConvertUTF16toUTF8(aIntegrityAttr).get()));
nsAutoCString sourceUri;
if (mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
SRICheck::IntegrityMetadata(aIntegrityAttr, sourceUri, mReporter,
aMetadataOut);
}
namespace {
class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable
@ -3164,7 +3129,16 @@ ScriptLoader::PreloadURI(nsIURI* aURI, const nsAString& aCharset,
}
SRIMetadata sriMetadata;
GetSRIMetadata(aIntegrity, &sriMetadata);
if (!aIntegrity.IsEmpty()) {
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
("ScriptLoader::PreloadURI, integrity=%s",
NS_ConvertUTF16toUTF8(aIntegrity).get()));
nsAutoCString sourceUri;
if (mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
SRICheck::IntegrityMetadata(aIntegrity, sourceUri, mReporter, &sriMetadata);
}
RefPtr<ScriptLoadRequest> request =
CreateLoadRequest(ScriptKind::eClassic, aURI, nullptr,

View File

@ -357,20 +357,6 @@ private:
void ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest);
bool ProcessExternalScript(nsIScriptElement* aElement,
ScriptKind aScriptKind,
nsAutoString aTypeAttr,
nsIContent* aScriptContent);
bool ProcessInlineScript(nsIScriptElement* aElement,
ScriptKind aScriptKind);
ScriptLoadRequest* LookupPreloadRequest(nsIScriptElement* aElement,
ScriptKind aScriptKind);
void GetSRIMetadata(const nsAString& aIntegrityAttr,
SRIMetadata *aMetadataOut);
/**
* Helper function to check the content policy for a given request.
*/