Index: third_party/WebKit/Source/core/dom/ScriptLoader.cpp |
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp |
index 556fd9b9bc08b85524bea725d0620f317f46dbbf..c7efab3ec63333965efd28f00a469fa483a4b8b3 100644 |
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp |
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp |
@@ -41,11 +41,9 @@ |
#include "core/frame/UseCounter.h" |
#include "core/frame/csp/ContentSecurityPolicy.h" |
#include "core/html/CrossOriginAttribute.h" |
-#include "core/html/HTMLScriptElement.h" |
#include "core/html/imports/HTMLImport.h" |
#include "core/html/parser/HTMLParserIdioms.h" |
#include "core/inspector/ConsoleMessage.h" |
-#include "core/svg/SVGScriptElement.h" |
#include "platform/WebFrameScheduler.h" |
#include "platform/loader/fetch/AccessControlStatus.h" |
#include "platform/loader/fetch/FetchRequest.h" |
@@ -60,11 +58,11 @@ |
namespace blink { |
-ScriptLoader::ScriptLoader(Element* element, |
+ScriptLoader::ScriptLoader(ScriptLoaderClient* client, |
bool parserInserted, |
bool alreadyStarted, |
bool createdDuringDocumentWrite) |
- : m_element(element), |
+ : m_client(client), |
m_startLineNumber(WTF::OrdinalNumber::beforeFirst()), |
m_haveFiredLoad(false), |
m_willBeParserExecuted(false), |
@@ -73,7 +71,7 @@ ScriptLoader::ScriptLoader(Element* element, |
m_asyncExecType(ScriptRunner::None), |
m_documentWriteIntervention( |
DocumentWriteIntervention::DocumentWriteInterventionNone) { |
- DCHECK(m_element); |
+ DCHECK(m_client); |
// https://html.spec.whatwg.org/#already-started |
// "The cloning steps for script elements must set the "already started" |
@@ -96,16 +94,17 @@ ScriptLoader::ScriptLoader(Element* element, |
m_nonBlocking = false; |
} |
- if (parserInserted && element->document().scriptableDocumentParser() && |
- !element->document().isInDocumentWrite()) |
+ if (parserInserted && m_client->document().scriptableDocumentParser() && |
+ !m_client->document().isInDocumentWrite()) { |
m_startLineNumber = |
- element->document().scriptableDocumentParser()->lineNumber(); |
+ m_client->document().scriptableDocumentParser()->lineNumber(); |
+ } |
} |
ScriptLoader::~ScriptLoader() {} |
DEFINE_TRACE(ScriptLoader) { |
- visitor->trace(m_element); |
+ visitor->trace(m_client); |
visitor->trace(m_resource); |
visitor->trace(m_pendingScript); |
PendingScriptClient::trace(visitor); |
@@ -123,7 +122,7 @@ void ScriptLoader::didNotifySubtreeInsertionsToDocument() { |
} |
void ScriptLoader::childrenChanged() { |
- if (!m_parserInserted && m_element->isConnected()) |
+ if (!m_parserInserted && m_client->isConnected()) |
prepareScript(); // FIXME: Provide a real starting line number here. |
} |
@@ -175,12 +174,11 @@ static bool isLegacySupportedJavaScriptLanguage(const String& language) { |
} |
void ScriptLoader::dispatchErrorEvent() { |
- m_element->dispatchEvent(Event::create(EventTypeNames::error)); |
+ m_client->dispatchErrorEvent(); |
} |
void ScriptLoader::dispatchLoadEvent() { |
- if (ScriptLoaderClient* client = this->client()) |
hiroshige
2017/03/01 00:58:14
So client() was always non-null and this if condit
Nate Chapin
2017/03/01 21:34:59
I believe so. I guess if buggy code had constructo
|
- client->dispatchLoadEvent(); |
+ m_client->dispatchLoadEvent(); |
setHaveFiredLoadEvent(true); |
} |
@@ -215,8 +213,8 @@ bool ScriptLoader::isValidScriptTypeAndLanguage( |
bool ScriptLoader::isScriptTypeSupported( |
LegacyTypeSupport supportLegacyTypes) const { |
- return isValidScriptTypeAndLanguage(client()->typeAttributeValue(), |
- client()->languageAttributeValue(), |
+ return isValidScriptTypeAndLanguage(m_client->typeAttributeValue(), |
+ m_client->languageAttributeValue(), |
supportLegacyTypes); |
} |
@@ -228,8 +226,6 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
if (m_alreadyStarted) |
return false; |
- ScriptLoaderClient* client = this->client(); |
- |
// 2. "If the element has its "parser-inserted" flag set, then |
// set was-parser-inserted to true and unset the element's |
// "parser-inserted" flag. |
@@ -244,7 +240,7 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// 3. "If was-parser-inserted is true and the element does not have an |
// async attribute, then set the element's "non-blocking" flag to true." |
- if (wasParserInserted && !client->asyncAttributeValue()) |
+ if (wasParserInserted && !m_client->asyncAttributeValue()) |
m_nonBlocking = true; |
// 4. "If the element has no src attribute, and its child nodes, if any, |
@@ -252,12 +248,12 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// then abort these steps at this point. The script is not executed." |
// FIXME: HTML5 spec says we should check that all children are either |
// comments or empty text nodes. |
- if (!client->hasSourceAttribute() && !m_element->hasChildren()) |
+ if (!m_client->hasSourceAttribute() && !m_client->hasChildren()) |
return false; |
// 5. "If the element is not connected, then abort these steps. |
// The script is not executed." |
- if (!m_element->isConnected()) |
+ if (!m_client->isConnected()) |
return false; |
// 6. |
@@ -281,14 +277,14 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// then abort these steps." |
// FIXME: If script is parser inserted, verify it's still in the original |
// document. |
- Document& elementDocument = m_element->document(); |
+ Document& elementDocument = m_client->document(); |
Document* contextDocument = elementDocument.contextDocument(); |
if (!contextDocument) |
return false; |
// 10. "If scripting is disabled for the script element, then abort these |
// steps at this point. The script is not executed." |
- if (!contextDocument->allowExecutingScripts(m_element)) |
+ if (!contextDocument->allowExecutingScripts(&elementDocument)) |
return false; |
// 13. |
@@ -303,23 +299,23 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// be the same as the encoding of the script element's node document." |
// TODO(hiroshige): Should we handle failure in getting an encoding? |
String encoding; |
- if (!client->charsetAttributeValue().isEmpty()) |
- encoding = client->charsetAttributeValue(); |
+ if (!m_client->charsetAttributeValue().isEmpty()) |
+ encoding = m_client->charsetAttributeValue(); |
else |
encoding = elementDocument.characterSet(); |
// Steps 15--20 are handled in fetchScript(). |
// 21. "If the element has a src content attribute, run these substeps:" |
- if (client->hasSourceAttribute()) { |
+ if (m_client->hasSourceAttribute()) { |
FetchRequest::DeferOption defer = FetchRequest::NoDefer; |
- if (!m_parserInserted || client->asyncAttributeValue() || |
- client->deferAttributeValue()) |
+ if (!m_parserInserted || m_client->asyncAttributeValue() || |
+ m_client->deferAttributeValue()) |
defer = FetchRequest::LazyLoad; |
if (m_documentWriteIntervention == |
DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) |
defer = FetchRequest::IdleLoad; |
- if (!fetchScript(client->sourceAttributeValue(), encoding, defer)) |
+ if (!fetchScript(m_client->sourceAttributeValue(), encoding, defer)) |
return false; |
} |
@@ -351,7 +347,7 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// completion to be able to remove it from the memory cache. |
if (m_documentWriteIntervention == |
DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) { |
- m_pendingScript = PendingScript::create(m_element, m_resource.get()); |
+ m_pendingScript = PendingScript::create(m_client.get(), m_resource.get()); |
m_pendingScript->watchForLoad(this); |
return true; |
} |
@@ -372,8 +368,8 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// and the element has been flagged as "parser-inserted", |
// and the element does not have an async attribute" |
// TODO(hiroshige): Check the script's type and implement "module" case. |
- if (client->hasSourceAttribute() && client->deferAttributeValue() && |
- m_parserInserted && !client->asyncAttributeValue()) { |
+ if (m_client->hasSourceAttribute() && m_client->deferAttributeValue() && |
+ m_parserInserted && !m_client->asyncAttributeValue()) { |
// This clause is implemented by the caller-side of prepareScript(): |
// - HTMLParserScriptRunner::requestDeferredScript(), and |
// - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() |
@@ -389,8 +385,8 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// and the element has been flagged as "parser-inserted", |
// and the element does not have an async attribute" |
// TODO(hiroshige): Check the script's type. |
- if (client->hasSourceAttribute() && m_parserInserted && |
- !client->asyncAttributeValue()) { |
+ if (m_client->hasSourceAttribute() && m_parserInserted && |
+ !m_client->asyncAttributeValue()) { |
// This clause is implemented by the caller-side of prepareScript(): |
// - HTMLParserScriptRunner::requestParsingBlockingScript() |
// - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() |
@@ -413,7 +409,7 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// Part of the condition check is done in |
// HTMLParserScriptRunner::processScriptElementInternal(). |
// TODO(hiroshige): Clean up the split condition check. |
- if (!client->hasSourceAttribute() && m_parserInserted && |
+ if (!m_client->hasSourceAttribute() && m_parserInserted && |
!elementDocument.isScriptExecutionReady()) { |
// The former part of this clause is |
// implemented by the caller-side of prepareScript(): |
@@ -432,12 +428,12 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// and the element does not have an async attribute, |
// and the element does not have the "non-blocking" flag set" |
// TODO(hiroshige): Check the script's type and implement "module" case. |
- if (client->hasSourceAttribute() && !client->asyncAttributeValue() && |
+ if (m_client->hasSourceAttribute() && !m_client->asyncAttributeValue() && |
!m_nonBlocking) { |
// "Add the element to the end of the list of scripts that will execute |
// in order as soon as possible associated with the node document of the |
// script element at the time the prepare a script algorithm started." |
- m_pendingScript = PendingScript::create(m_element, m_resource.get()); |
+ m_pendingScript = PendingScript::create(m_client.get(), m_resource.get()); |
m_asyncExecType = ScriptRunner::InOrder; |
// TODO(hiroshige): Here |contextDocument| is used as "node document" |
// while Step 14 uses |elementDocument| as "node document". Fix this. |
@@ -455,13 +451,13 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
// 4th Clause: |
// - "If the script's type is "classic", and the element has a src attribute" |
// TODO(hiroshige): Check the script's type and implement "module" case. |
- if (client->hasSourceAttribute()) { |
+ if (m_client->hasSourceAttribute()) { |
// "The element must be added to the set of scripts that will execute |
// as soon as possible of the node document of the script element at the |
// time the prepare a script algorithm started." |
- m_pendingScript = PendingScript::create(m_element, m_resource.get()); |
+ m_pendingScript = PendingScript::create(m_client.get(), m_resource.get()); |
m_asyncExecType = ScriptRunner::Async; |
- LocalFrame* frame = m_element->document().frame(); |
+ LocalFrame* frame = m_client->document().frame(); |
if (frame) { |
ScriptState* scriptState = ScriptState::forMainWorld(frame); |
if (scriptState) |
@@ -513,10 +509,8 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
bool ScriptLoader::fetchScript(const String& sourceUrl, |
const String& encoding, |
FetchRequest::DeferOption defer) { |
- DCHECK(m_element); |
- |
- Document* elementDocument = &(m_element->document()); |
- if (!m_element->isConnected() || m_element->document() != elementDocument) |
+ Document* elementDocument = &(m_client->document()); |
+ if (!m_client->isConnected() || m_client->document() != elementDocument) |
return false; |
DCHECK(!m_resource); |
@@ -525,12 +519,12 @@ bool ScriptLoader::fetchScript(const String& sourceUrl, |
// 21.4. "Parse src relative to the element's node document." |
FetchRequest request( |
ResourceRequest(elementDocument->completeURL(sourceUrl)), |
- m_element->localName()); |
+ m_client->initiatorName()); |
// 15. "Let CORS setting be the current state of the element's |
// crossorigin content attribute." |
- CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue( |
- m_element->fastGetAttribute(HTMLNames::crossoriginAttr)); |
+ CrossOriginAttributeValue crossOrigin = |
+ crossOriginAttributeValue(m_client->crossOriginAttributeValue()); |
// 16. "Let module script credentials mode be determined by switching |
// on CORS setting:" |
@@ -547,8 +541,8 @@ bool ScriptLoader::fetchScript(const String& sourceUrl, |
// 17. "If the script element has a nonce attribute, |
// then let cryptographic nonce be that attribute's value. |
// Otherwise, let cryptographic nonce be the empty string." |
- if (ContentSecurityPolicy::isNonceableElement(m_element.get())) |
- request.setContentSecurityPolicyNonce(client()->nonce()); |
+ if (m_client->isNonceableElement()) |
+ request.setContentSecurityPolicyNonce(m_client->nonce()); |
// 19. "Let parser state be "parser-inserted" |
// if the script element has been flagged as "parser-inserted", |
@@ -561,8 +555,7 @@ bool ScriptLoader::fetchScript(const String& sourceUrl, |
// 18. "If the script element has an integrity attribute, |
// then let integrity metadata be that attribute's value. |
// Otherwise, let integrity metadata be the empty string." |
- String integrityAttr = |
- m_element->fastGetAttribute(HTMLNames::integrityAttr); |
+ String integrityAttr = m_client->integrityAttributeValue(); |
if (!integrityAttr.isEmpty()) { |
IntegrityMetadataSet metadataSet; |
SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet, |
@@ -625,16 +618,6 @@ bool ScriptLoader::fetchScript(const String& sourceUrl, |
return true; |
} |
-bool isHTMLScriptLoader(Element* element) { |
- DCHECK(element); |
- return isHTMLScriptElement(*element); |
-} |
- |
-bool isSVGScriptLoader(Element* element) { |
- DCHECK(element); |
- return isSVGScriptElement(*element); |
-} |
- |
void ScriptLoader::logScriptMIMEType(LocalFrame* frame, |
ScriptResource* resource, |
const String& mimeType) { |
@@ -644,7 +627,7 @@ void ScriptLoader::logScriptMIMEType(LocalFrame* frame, |
if (isText && isLegacySupportedJavaScriptLanguage(mimeType.substring(5))) |
return; |
bool isSameOrigin = |
- m_element->document().getSecurityOrigin()->canRequest(resource->url()); |
+ m_client->document().getSecurityOrigin()->canRequest(resource->url()); |
bool isApplication = |
!isText && mimeType.startsWith("application/", TextCaseASCIIInsensitive); |
@@ -669,7 +652,7 @@ bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode) { |
// include inline script execution time as part of parser blocked script |
// execution time. |
if (m_asyncExecType == ScriptRunner::None) |
- DocumentParserTiming::from(m_element->document()) |
+ DocumentParserTiming::from(m_client->document()) |
.recordParserBlockedOnScriptExecutionDuration( |
monotonicallyIncreasingTime() - scriptExecStartTime, |
wasCreatedDuringDocumentWrite()); |
@@ -688,7 +671,7 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) { |
if (sourceCode.isEmpty()) |
return true; |
- Document* elementDocument = &(m_element->document()); |
+ Document* elementDocument = &(m_client->document()); |
Document* contextDocument = elementDocument->contextDocument(); |
if (!contextDocument) |
return true; |
@@ -704,13 +687,10 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) { |
ContentSecurityPolicy::InlineType::Block); |
AtomicString nonce = |
- ContentSecurityPolicy::isNonceableElement(m_element.get()) |
- ? client()->nonce() |
- : nullAtom; |
- if (!m_isExternalScript && |
- (!shouldBypassMainWorldCSP && |
- !csp->allowInlineScript(m_element, elementDocument->url(), nonce, |
- m_startLineNumber, sourceCode.source()))) { |
+ m_client->isNonceableElement() ? m_client->nonce() : nullAtom; |
+ if (!m_isExternalScript && !shouldBypassMainWorldCSP && |
+ !m_client->allowInlineScriptForCSP(nonce, m_startLineNumber, |
+ sourceCode.source())) { |
return false; |
} |
@@ -763,7 +743,7 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) { |
else |
accessControlStatus = SharableCrossOrigin; |
} else if (sourceCode.resource()->passesAccessControlCheck( |
- m_element->document().getSecurityOrigin())) { |
+ m_client->document().getSecurityOrigin())) { |
accessControlStatus = SharableCrossOrigin; |
} |
} |
@@ -787,8 +767,7 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) { |
// 1. "If the script element's root is not a shadow root, |
// then set the script element's node document's currentScript |
// attribute to the script element. Otherwise, set it to null." |
- if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element)) |
- contextDocument->pushCurrentScript(m_element); |
+ contextDocument->pushCurrentScript(m_client.get()); |
// 2. "Run the classic script given by the script's script." |
// Note: This is where the script is compiled and actually executed. |
@@ -799,10 +778,7 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) { |
// 6. "Set the script element's node document's currentScript attribute |
// to old script element." |
- if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element)) { |
- DCHECK(contextDocument->currentScript() == m_element); |
- contextDocument->popCurrentScript(); |
- } |
+ contextDocument->popCurrentScript(m_client.get()); |
return true; |
@@ -847,7 +823,7 @@ void ScriptLoader::pendingScriptFinished(PendingScript* pendingScript) { |
DCHECK(m_asyncExecType != ScriptRunner::None); |
- Document* contextDocument = m_element->document().contextDocument(); |
+ Document* contextDocument = m_client->document().contextDocument(); |
if (!contextDocument) { |
detachPendingScript(); |
return; |
@@ -866,15 +842,15 @@ void ScriptLoader::pendingScriptFinished(PendingScript* pendingScript) { |
bool ScriptLoader::ignoresLoadRequest() const { |
return m_alreadyStarted || m_isExternalScript || m_parserInserted || |
- !element() || !element()->isConnected(); |
+ !m_client->isConnected(); |
} |
// Step 13 of https://html.spec.whatwg.org/#prepare-a-script |
bool ScriptLoader::isScriptForEventSupported() const { |
// 1. "Let for be the value of the for attribute." |
- String eventAttribute = client()->eventAttributeValue(); |
+ String eventAttribute = m_client->eventAttributeValue(); |
// 2. "Let event be the value of the event attribute." |
- String forAttribute = client()->forAttributeValue(); |
+ String forAttribute = m_client->forAttributeValue(); |
// "If the script element has an event attribute and a for attribute, and |
// the script's type is "classic", then run these substeps:" |
@@ -898,28 +874,7 @@ bool ScriptLoader::isScriptForEventSupported() const { |
} |
String ScriptLoader::scriptContent() const { |
- return m_element->textFromChildren(); |
-} |
- |
-ScriptLoaderClient* ScriptLoader::client() const { |
- if (isHTMLScriptLoader(m_element)) |
- return toHTMLScriptElement(m_element); |
- |
- if (isSVGScriptLoader(m_element)) |
- return toSVGScriptElement(m_element); |
- |
- NOTREACHED(); |
- return 0; |
-} |
- |
-ScriptLoader* toScriptLoaderIfPossible(Element* element) { |
- if (isHTMLScriptLoader(element)) |
- return toHTMLScriptElement(element)->loader(); |
- |
- if (isSVGScriptLoader(element)) |
- return toSVGScriptElement(element)->loader(); |
- |
- return 0; |
+ return m_client->textFromChildren(); |
} |
} // namespace blink |