| 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 0a9402b302f3e530645f10d5a6397add4059de80..195eaf2e1b91684ada8b2c0e0849a925a7f7dac9 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,8 +71,6 @@ ScriptLoader::ScriptLoader(Element* element,
|
| m_asyncExecType(ScriptRunner::None),
|
| m_documentWriteIntervention(
|
| DocumentWriteIntervention::DocumentWriteInterventionNone) {
|
| - DCHECK(m_element);
|
| -
|
| // https://html.spec.whatwg.org/#already-started
|
| // "The cloning steps for script elements must set the "already started"
|
| // flag on the copy if it is set on the element being cloned."
|
| @@ -96,16 +92,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 +120,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 +172,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())
|
| - client->dispatchLoadEvent();
|
| + m_client->dispatchLoadEvent();
|
| setHaveFiredLoadEvent(true);
|
| }
|
|
|
| @@ -215,8 +211,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 +224,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 +238,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 +246,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 +275,16 @@ 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)
|
| + if (!elementDocument.executingFrame())
|
| + return false;
|
| + if (!contextDocument || !contextDocument->executingFrame())
|
| 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->canExecuteScripts(AboutToExecuteScript))
|
| 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;
|
| }
|
|
|
| @@ -762,7 +742,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;
|
| }
|
| }
|
| @@ -786,8 +766,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.
|
| @@ -798,10 +777,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;
|
|
|
| @@ -846,7 +822,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;
|
| @@ -865,15 +841,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:"
|
| @@ -897,28 +873,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
|
|
|