Chromium Code Reviews| 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 |