diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/dom/ScriptElement.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/dom/ScriptElement.cpp')
-rw-r--r-- | Source/WebCore/dom/ScriptElement.cpp | 425 |
1 files changed, 251 insertions, 174 deletions
diff --git a/Source/WebCore/dom/ScriptElement.cpp b/Source/WebCore/dom/ScriptElement.cpp index 651cc5806..cf51d40d5 100644 --- a/Source/WebCore/dom/ScriptElement.cpp +++ b/Source/WebCore/dom/ScriptElement.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003-2017 Apple Inc. All rights reserved. * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> * * This library is free software; you can redistribute it and/or @@ -24,43 +24,39 @@ #include "config.h" #include "ScriptElement.h" -#include "CachedScript.h" #include "CachedResourceLoader.h" #include "CachedResourceRequest.h" +#include "CachedScript.h" #include "ContentSecurityPolicy.h" #include "CrossOriginAccessControl.h" #include "CurrentScriptIncrementer.h" #include "Event.h" +#include "EventNames.h" #include "Frame.h" #include "FrameLoader.h" #include "HTMLNames.h" #include "HTMLParserIdioms.h" #include "IgnoreDestructiveWriteCountIncrementer.h" +#include "InlineClassicScript.h" +#include "LoadableClassicScript.h" +#include "LoadableModuleScript.h" #include "MIMETypeRegistry.h" -#include "Page.h" -#include "ScriptCallStack.h" +#include "NoEventDispatchAssertion.h" +#include "PendingScript.h" +#include "SVGScriptElement.h" #include "ScriptController.h" #include "ScriptRunner.h" #include "ScriptSourceCode.h" #include "ScriptableDocumentParser.h" -#include "SecurityOrigin.h" -#include "Settings.h" #include "TextNodeTraversal.h" -#include <bindings/ScriptValue.h> #include <wtf/StdLibExtras.h> #include <wtf/text/StringBuilder.h> #include <wtf/text/StringHash.h> -#if ENABLE(SVG) -#include "SVGNames.h" -#include "SVGScriptElement.h" -#endif - namespace WebCore { -ScriptElement::ScriptElement(Element* element, bool parserInserted, bool alreadyStarted) +ScriptElement::ScriptElement(Element& element, bool parserInserted, bool alreadyStarted) : m_element(element) - , m_cachedScript(0) , m_startLineNumber(WTF::OrdinalNumber::beforeFirst()) , m_parserInserted(parserInserted) , m_isExternalScript(false) @@ -71,38 +67,32 @@ ScriptElement::ScriptElement(Element* element, bool parserInserted, bool already , m_willExecuteWhenDocumentFinishedParsing(false) , m_forceAsync(!parserInserted) , m_willExecuteInOrder(false) - , m_requestUsesAccessControl(false) + , m_isModuleScript(false) { - ASSERT(m_element); - if (parserInserted && m_element->document().scriptableDocumentParser() && !m_element->document().isInDocumentWrite()) - m_startLineNumber = m_element->document().scriptableDocumentParser()->textPosition().m_line; + if (parserInserted && m_element.document().scriptableDocumentParser() && !m_element.document().isInDocumentWrite()) + m_startLineNumber = m_element.document().scriptableDocumentParser()->textPosition().m_line; } -ScriptElement::~ScriptElement() +bool ScriptElement::shouldCallFinishedInsertingSubtree(ContainerNode& insertionPoint) { - stopLoadRequest(); + return insertionPoint.isConnected() && !m_parserInserted; } -bool ScriptElement::shouldNotifySubtreeInsertions(ContainerNode& insertionPoint) -{ - return insertionPoint.inDocument() && !m_parserInserted; -} - -void ScriptElement::didNotifySubtreeInsertions(ContainerNode*) +void ScriptElement::finishedInsertingSubtree() { ASSERT(!m_parserInserted); prepareScript(); // FIXME: Provide a real starting line number here. } -void ScriptElement::childrenChanged() +void ScriptElement::childrenChanged(const ContainerNode::ChildChange& childChange) { - if (!m_parserInserted && m_element->inDocument()) + if (!m_parserInserted && childChange.isInsertion() && m_element.isConnected()) prepareScript(); // FIXME: Provide a real starting line number here. } -void ScriptElement::handleSourceAttribute(const String& sourceUrl) +void ScriptElement::handleSourceAttribute(const String& sourceURL) { - if (ignoresLoadRequest() || sourceUrl.isEmpty()) + if (ignoresLoadRequest() || sourceURL.isEmpty()) return; prepareScript(); // FIXME: Provide a real starting line number here. @@ -123,49 +113,65 @@ static bool isLegacySupportedJavaScriptLanguage(const String& language) // We want to accept all the values that either of these browsers accept, but not other values. // FIXME: This function is not HTML5 compliant. These belong in the MIME registry as "text/javascript<version>" entries. - typedef HashSet<String, CaseFoldingHash> LanguageSet; - DEFINE_STATIC_LOCAL(LanguageSet, languages, ()); - if (languages.isEmpty()) { - languages.add("javascript"); - languages.add("javascript"); - languages.add("javascript1.0"); - languages.add("javascript1.1"); - languages.add("javascript1.2"); - languages.add("javascript1.3"); - languages.add("javascript1.4"); - languages.add("javascript1.5"); - languages.add("javascript1.6"); - languages.add("javascript1.7"); - languages.add("livescript"); - languages.add("ecmascript"); - languages.add("jscript"); + typedef HashSet<String, ASCIICaseInsensitiveHash> LanguageSet; + static NeverDestroyed<LanguageSet> languages; + if (languages.get().isEmpty()) { + languages.get().add("javascript"); + languages.get().add("javascript"); + languages.get().add("javascript1.0"); + languages.get().add("javascript1.1"); + languages.get().add("javascript1.2"); + languages.get().add("javascript1.3"); + languages.get().add("javascript1.4"); + languages.get().add("javascript1.5"); + languages.get().add("javascript1.6"); + languages.get().add("javascript1.7"); + languages.get().add("livescript"); + languages.get().add("ecmascript"); + languages.get().add("jscript"); } - return languages.contains(language); + return languages.get().contains(language); } void ScriptElement::dispatchErrorEvent() { - m_element->dispatchEvent(Event::create(eventNames().errorEvent, false, false)); + m_element.dispatchEvent(Event::create(eventNames().errorEvent, false, false)); } -bool ScriptElement::isScriptTypeSupported(LegacyTypeSupport supportLegacyTypes) const +std::optional<ScriptElement::ScriptType> ScriptElement::determineScriptType(LegacyTypeSupport supportLegacyTypes) const { // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used here to maintain backwards compatibility with existing layout tests. The specific violations are: // - Allowing type=javascript. type= should only support MIME types, such as text/javascript. // - Allowing a different set of languages for language= and type=. language= supports Javascript 1.1 and 1.4-1.6, but type= does not. - String type = typeAttributeValue(); String language = languageAttributeValue(); - if (type.isEmpty() && language.isEmpty()) - return true; // Assume text/javascript. if (type.isEmpty()) { - type = "text/" + language.lower(); - if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type) || isLegacySupportedJavaScriptLanguage(language)) - return true; - } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type.stripWhiteSpace().lower()) || (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && isLegacySupportedJavaScriptLanguage(type))) - return true; - return false; + if (language.isEmpty()) + return ScriptType::Classic; // Assume text/javascript. + if (MIMETypeRegistry::isSupportedJavaScriptMIMEType("text/" + language)) + return ScriptType::Classic; + if (isLegacySupportedJavaScriptLanguage(language)) + return ScriptType::Classic; + return std::nullopt; + } + if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type.stripWhiteSpace())) + return ScriptType::Classic; + if (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && isLegacySupportedJavaScriptLanguage(type)) + return ScriptType::Classic; + + // FIXME: XHTML spec defines "defer" attribute. But WebKit does not implement it for a long time. + // And module tag also uses defer attribute semantics. We disable script type="module" for non HTML document. + // Once "defer" is implemented, we can reconsider enabling modules in XHTML. + // https://bugs.webkit.org/show_bug.cgi?id=123387 + if (!m_element.document().isHTMLDocument()) + return std::nullopt; + + // https://html.spec.whatwg.org/multipage/scripting.html#attr-script-type + // Setting the attribute to an ASCII case-insensitive match for the string "module" means that the script is a module script. + if (equalLettersIgnoringASCIICase(type, "module")) + return ScriptType::Module; + return std::nullopt; } // http://dev.w3.org/html5/spec/Overview.html#prepare-a-script @@ -181,18 +187,22 @@ bool ScriptElement::prepareScript(const TextPosition& scriptStartPosition, Legac } else wasParserInserted = false; - if (wasParserInserted && !asyncAttributeValue()) + if (wasParserInserted && !hasAsyncAttribute()) m_forceAsync = true; // FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes. - if (!hasSourceAttribute() && !m_element->firstChild()) + if (!hasSourceAttribute() && !m_element.firstChild()) return false; - if (!m_element->inDocument()) + if (!m_element.isConnected()) return false; - if (!isScriptTypeSupported(supportLegacyTypes)) + ScriptType scriptType = ScriptType::Classic; + if (std::optional<ScriptType> result = determineScriptType(supportLegacyTypes)) + scriptType = result.value(); + else return false; + m_isModuleScript = scriptType == ScriptType::Module; if (wasParserInserted) { m_parserInserted = true; @@ -202,7 +212,7 @@ bool ScriptElement::prepareScript(const TextPosition& scriptStartPosition, Legac m_alreadyStarted = true; // FIXME: If script is parser inserted, verify it's still in the original document. - Document& document = m_element->document(); + Document& document = m_element.document(); // FIXME: Eventually we'd like to evaluate scripts which are inserted into a // viewless document but this'll do for now. @@ -210,180 +220,235 @@ bool ScriptElement::prepareScript(const TextPosition& scriptStartPosition, Legac if (!document.frame()) return false; + if (scriptType == ScriptType::Classic && hasNoModuleAttribute()) + return false; + if (!document.frame()->script().canExecuteScripts(AboutToExecuteScript)) return false; - if (!isScriptForEventSupported()) + if (scriptType == ScriptType::Classic && !isScriptForEventSupported()) return false; + // According to the spec, the module tag ignores the "charset" attribute as the same to the worker's + // importScript. But WebKit supports the "charset" for importScript intentionally. So to be consistent, + // even for the module tags, we handle the "charset" attribute. if (!charsetAttributeValue().isEmpty()) m_characterEncoding = charsetAttributeValue(); else m_characterEncoding = document.charset(); - if (hasSourceAttribute()) - if (!requestScript(sourceAttributeValue())) + if (scriptType == ScriptType::Classic) { + if (hasSourceAttribute()) { + if (!requestClassicScript(sourceAttributeValue())) + return false; + } + } else { + ASSERT(scriptType == ScriptType::Module); + if (!requestModuleScript(scriptStartPosition)) return false; + } + + // All the inlined module script is handled by requestModuleScript. It produces LoadableModuleScript and inlined module script + // is handled as the same to the external module script. - if (hasSourceAttribute() && deferAttributeValue() && m_parserInserted && !asyncAttributeValue()) { + bool isClassicExternalScript = scriptType == ScriptType::Classic && hasSourceAttribute(); + bool isParserInsertedDeferredScript = ((isClassicExternalScript && hasDeferAttribute()) || scriptType == ScriptType::Module) + && m_parserInserted && !hasAsyncAttribute(); + if (isParserInsertedDeferredScript) { m_willExecuteWhenDocumentFinishedParsing = true; m_willBeParserExecuted = true; - } else if (hasSourceAttribute() && m_parserInserted && !asyncAttributeValue()) + } else if (isClassicExternalScript && m_parserInserted && !hasAsyncAttribute()) { + ASSERT(scriptType == ScriptType::Classic); m_willBeParserExecuted = true; - else if (!hasSourceAttribute() && m_parserInserted && !document.haveStylesheetsLoaded()) { + } else if ((isClassicExternalScript || scriptType == ScriptType::Module) && !hasAsyncAttribute() && !m_forceAsync) { + m_willExecuteInOrder = true; + ASSERT(m_loadableScript); + document.scriptRunner()->queueScriptForExecution(*this, *m_loadableScript, ScriptRunner::IN_ORDER_EXECUTION); + } else if (hasSourceAttribute() || scriptType == ScriptType::Module) { + ASSERT(m_loadableScript); + ASSERT(hasAsyncAttribute() || m_forceAsync); + document.scriptRunner()->queueScriptForExecution(*this, *m_loadableScript, ScriptRunner::ASYNC_EXECUTION); + } else if (!hasSourceAttribute() && m_parserInserted && !document.haveStylesheetsLoaded()) { + ASSERT(scriptType == ScriptType::Classic); m_willBeParserExecuted = true; m_readyToBeParserExecuted = true; - } else if (hasSourceAttribute() && !asyncAttributeValue() && !m_forceAsync) { - m_willExecuteInOrder = true; - document.scriptRunner()->queueScriptForExecution(this, m_cachedScript, ScriptRunner::IN_ORDER_EXECUTION); - m_cachedScript->addClient(this); - } else if (hasSourceAttribute()) { - m_element->document().scriptRunner()->queueScriptForExecution(this, m_cachedScript, ScriptRunner::ASYNC_EXECUTION); - m_cachedScript->addClient(this); } else { - // Reset line numbering for nested writes. + ASSERT(scriptType == ScriptType::Classic); TextPosition position = document.isInDocumentWrite() ? TextPosition() : scriptStartPosition; - executeScript(ScriptSourceCode(scriptContent(), document.url(), position)); + executeClassicScript(ScriptSourceCode(scriptContent(), document.url(), position, JSC::SourceProviderSourceType::Program, InlineClassicScript::create(*this))); } return true; } -bool ScriptElement::requestScript(const String& sourceUrl) +bool ScriptElement::requestClassicScript(const String& sourceURL) { - Ref<Document> originalDocument(m_element->document()); - if (!m_element->dispatchBeforeLoadEvent(sourceUrl)) - return false; - if (!m_element->inDocument() || &m_element->document() != &originalDocument.get()) + Ref<Document> originalDocument(m_element.document()); + if (!m_element.dispatchBeforeLoadEvent(sourceURL)) return false; - if (!m_element->document().contentSecurityPolicy()->allowScriptNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr), m_element->document().url(), m_startLineNumber, m_element->document().completeURL(sourceUrl))) + bool didEventListenerDisconnectThisElement = !m_element.isConnected() || &m_element.document() != originalDocument.ptr(); + if (didEventListenerDisconnectThisElement) return false; - ASSERT(!m_cachedScript); - if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) { - CachedResourceRequest request(ResourceRequest(m_element->document().completeURL(sourceUrl))); + ASSERT(!m_loadableScript); + if (!stripLeadingAndTrailingHTMLSpaces(sourceURL).isEmpty()) { + auto script = LoadableClassicScript::create( + m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr), + m_element.attributeWithoutSynchronization(HTMLNames::crossoriginAttr), + scriptCharset(), + m_element.localName(), + m_element.isInUserAgentShadowTree()); + if (script->load(m_element.document(), m_element.document().completeURL(sourceURL))) { + m_loadableScript = WTFMove(script); + m_isExternalScript = true; + } + } + + if (m_loadableScript) + return true; - String crossOriginMode = m_element->fastGetAttribute(HTMLNames::crossoriginAttr); - if (!crossOriginMode.isNull()) { - m_requestUsesAccessControl = true; - StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials; - updateRequestForAccessControl(request.mutableResourceRequest(), m_element->document().securityOrigin(), allowCredentials); + callOnMainThread([this, element = Ref<Element>(m_element)] { + dispatchErrorEvent(); + }); + return false; +} + +bool ScriptElement::requestModuleScript(const TextPosition& scriptStartPosition) +{ + String nonce = m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr); + String crossOriginMode = m_element.attributeWithoutSynchronization(HTMLNames::crossoriginAttr); + if (crossOriginMode.isNull()) + crossOriginMode = ASCIILiteral("omit"); + + if (hasSourceAttribute()) { + String sourceURL = sourceAttributeValue(); + Ref<Document> originalDocument(m_element.document()); + if (!m_element.dispatchBeforeLoadEvent(sourceURL)) + return false; + + bool didEventListenerDisconnectThisElement = !m_element.isConnected() || &m_element.document() != originalDocument.ptr(); + if (didEventListenerDisconnectThisElement) + return false; + + if (stripLeadingAndTrailingHTMLSpaces(sourceURL).isEmpty()) { + dispatchErrorEvent(); + return false; } - request.setCharset(scriptCharset()); - request.setInitiator(element()); - m_cachedScript = m_element->document().cachedResourceLoader()->requestScript(request); - m_isExternalScript = true; - } + auto moduleScriptRootURL = m_element.document().completeURL(sourceURL); + if (!moduleScriptRootURL.isValid()) { + dispatchErrorEvent(); + return false; + } - if (m_cachedScript) { + m_isExternalScript = true; + auto script = LoadableModuleScript::create(nonce, crossOriginMode, scriptCharset(), m_element.localName(), m_element.isInUserAgentShadowTree()); + script->load(m_element.document(), moduleScriptRootURL); + m_loadableScript = WTFMove(script); return true; } - dispatchErrorEvent(); - return false; + auto script = LoadableModuleScript::create(nonce, crossOriginMode, scriptCharset(), m_element.localName(), m_element.isInUserAgentShadowTree()); + + TextPosition position = m_element.document().isInDocumentWrite() ? TextPosition() : scriptStartPosition; + ScriptSourceCode sourceCode(scriptContent(), m_element.document().url(), position, JSC::SourceProviderSourceType::Module, script.copyRef()); + + ASSERT(m_element.document().contentSecurityPolicy()); + const auto& contentSecurityPolicy = *m_element.document().contentSecurityPolicy(); + bool hasKnownNonce = contentSecurityPolicy.allowScriptWithNonce(nonce, m_element.isInUserAgentShadowTree()); + if (!contentSecurityPolicy.allowInlineScript(m_element.document().url(), m_startLineNumber, sourceCode.source().toStringWithoutCopying(), hasKnownNonce)) + return false; + + script->load(m_element.document(), sourceCode); + m_loadableScript = WTFMove(script); + return true; } -void ScriptElement::executeScript(const ScriptSourceCode& sourceCode) +void ScriptElement::executeClassicScript(const ScriptSourceCode& sourceCode) { + ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::isEventAllowedInMainThread()); ASSERT(m_alreadyStarted); if (sourceCode.isEmpty()) return; - if (!m_element->document().contentSecurityPolicy()->allowScriptNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr), m_element->document().url(), m_startLineNumber)) - return; + if (!m_isExternalScript) { + ASSERT(m_element.document().contentSecurityPolicy()); + const ContentSecurityPolicy& contentSecurityPolicy = *m_element.document().contentSecurityPolicy(); + bool hasKnownNonce = contentSecurityPolicy.allowScriptWithNonce(m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr), m_element.isInUserAgentShadowTree()); + if (!contentSecurityPolicy.allowInlineScript(m_element.document().url(), m_startLineNumber, sourceCode.source().toStringWithoutCopying(), hasKnownNonce)) + return; + } - if (!m_isExternalScript && !m_element->document().contentSecurityPolicy()->allowInlineScript(m_element->document().url(), m_startLineNumber)) + auto& document = m_element.document(); + auto* frame = document.frame(); + if (!frame) return; -#if ENABLE(NOSNIFF) - if (m_isExternalScript && m_cachedScript && !m_cachedScript->mimeTypeAllowedByNosniff()) { - m_element->document().addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + m_cachedScript->url().stringCenterEllipsizedToLength() + "' because its MIME type ('" + m_cachedScript->mimeType() + "') is not executable, and strict MIME type checking is enabled."); - return; - } -#endif + IgnoreDestructiveWriteCountIncrementer ignoreDesctructiveWriteCountIncrementer(m_isExternalScript ? &document : nullptr); + CurrentScriptIncrementer currentScriptIncrementer(document, m_element); - Ref<Document> document(m_element->document()); - if (Frame* frame = document->frame()) { - IgnoreDestructiveWriteCountIncrementer ignoreDesctructiveWriteCountIncrementer(m_isExternalScript ? &document.get() : 0); - CurrentScriptIncrementer currentScriptIncrementer(&document.get(), m_element); - - // Create a script from the script element node, using the script - // block's source and the script block's type. - // Note: This is where the script is compiled and actually executed. - frame->script().evaluate(sourceCode); - } + frame->script().evaluate(sourceCode); } -void ScriptElement::stopLoadRequest() +void ScriptElement::executeModuleScript(LoadableModuleScript& loadableModuleScript) { - if (m_cachedScript) { - if (!m_willBeParserExecuted) - m_cachedScript->removeClient(this); - m_cachedScript = 0; - } + // https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-block + + ASSERT(!loadableModuleScript.error()); + + auto& document = m_element.document(); + auto* frame = document.frame(); + if (!frame) + return; + + IgnoreDestructiveWriteCountIncrementer ignoreDesctructiveWriteCountIncrementer(&document); + CurrentScriptIncrementer currentScriptIncrementer(document, m_element); + + frame->script().linkAndEvaluateModuleScript(loadableModuleScript); } -void ScriptElement::execute(CachedScript* cachedScript) +void ScriptElement::executeScriptAndDispatchEvent(LoadableScript& loadableScript) { - ASSERT(!m_willBeParserExecuted); - ASSERT(cachedScript); - if (cachedScript->errorOccurred()) + if (std::optional<LoadableScript::Error> error = loadableScript.error()) { + if (std::optional<LoadableScript::ConsoleMessage> message = error->consoleMessage) + m_element.document().addConsoleMessage(message->source, message->level, message->message); dispatchErrorEvent(); - else if (!cachedScript->wasCanceled()) { - executeScript(ScriptSourceCode(cachedScript)); + } else if (!loadableScript.wasCanceled()) { + ASSERT(!loadableScript.error()); + loadableScript.execute(*this); dispatchLoadEvent(); } - cachedScript->removeClient(this); } -void ScriptElement::notifyFinished(CachedResource* resource) +void ScriptElement::executePendingScript(PendingScript& pendingScript) { - ASSERT(!m_willBeParserExecuted); - - // CachedResource possibly invokes this notifyFinished() more than - // once because ScriptElement doesn't unsubscribe itself from - // CachedResource here and does it in execute() instead. - // We use m_cachedScript to check if this function is already called. - ASSERT_UNUSED(resource, resource == m_cachedScript); - if (!m_cachedScript) - return; - - if (m_requestUsesAccessControl - && !m_element->document().securityOrigin()->canRequest(m_cachedScript->response().url()) - && !m_cachedScript->passesAccessControlCheck(m_element->document().securityOrigin())) { - - dispatchErrorEvent(); - DEFINE_STATIC_LOCAL(String, consoleMessage, (ASCIILiteral("Cross-origin script load denied by Cross-Origin Resource Sharing policy."))); - m_element->document().addConsoleMessage(JSMessageSource, ErrorMessageLevel, consoleMessage); - return; + if (auto* loadableScript = pendingScript.loadableScript()) + executeScriptAndDispatchEvent(*loadableScript); + else { + ASSERT(!pendingScript.error()); + ASSERT_WITH_MESSAGE(scriptType() == ScriptType::Classic, "Module script always have a loadableScript pointer."); + executeClassicScript(ScriptSourceCode(scriptContent(), m_element.document().url(), pendingScript.startingPosition(), JSC::SourceProviderSourceType::Program, InlineClassicScript::create(*this))); + dispatchLoadEvent(); } - - if (m_willExecuteInOrder) - m_element->document().scriptRunner()->notifyScriptReady(this, ScriptRunner::IN_ORDER_EXECUTION); - else - m_element->document().scriptRunner()->notifyScriptReady(this, ScriptRunner::ASYNC_EXECUTION); - - m_cachedScript = 0; } bool ScriptElement::ignoresLoadRequest() const { - return m_alreadyStarted || m_isExternalScript || m_parserInserted || !m_element->inDocument(); + return m_alreadyStarted || m_isExternalScript || m_parserInserted || !m_element.isConnected(); } bool ScriptElement::isScriptForEventSupported() const { String eventAttribute = eventAttributeValue(); String forAttribute = forAttributeValue(); - if (!eventAttribute.isEmpty() && !forAttribute.isEmpty()) { - forAttribute = forAttribute.stripWhiteSpace(); - if (!equalIgnoringCase(forAttribute, "window")) + if (!eventAttribute.isNull() && !forAttribute.isNull()) { + forAttribute = stripLeadingAndTrailingHTMLSpaces(forAttribute); + if (!equalLettersIgnoringASCIICase(forAttribute, "window")) return false; - eventAttribute = eventAttribute.stripWhiteSpace(); - if (!equalIgnoringCase(eventAttribute, "onload") && !equalIgnoringCase(eventAttribute, "onload()")) + eventAttribute = stripLeadingAndTrailingHTMLSpaces(eventAttribute); + if (!equalLettersIgnoringASCIICase(eventAttribute, "onload") && !equalLettersIgnoringASCIICase(eventAttribute, "onload()")) return false; } return true; @@ -391,20 +456,32 @@ bool ScriptElement::isScriptForEventSupported() const String ScriptElement::scriptContent() const { - return TextNodeTraversal::contentsAsString(m_element); + StringBuilder result; + for (auto* text = TextNodeTraversal::firstChild(m_element); text; text = TextNodeTraversal::nextSibling(*text)) + result.append(text->data()); + return result.toString(); } -ScriptElement* toScriptElementIfPossible(Element* element) +void ScriptElement::ref() { - if (isHTMLScriptElement(element)) - return toHTMLScriptElement(element); + m_element.ref(); +} -#if ENABLE(SVG) - if (isSVGScriptElement(element)) - return toSVGScriptElement(element); -#endif +void ScriptElement::deref() +{ + m_element.deref(); +} - return 0; +bool isScriptElement(Element& element) +{ + return is<HTMLScriptElement>(element) || is<SVGScriptElement>(element); +} + +ScriptElement& downcastScriptElement(Element& element) +{ + if (is<HTMLScriptElement>(element)) + return downcast<HTMLScriptElement>(element); + return downcast<SVGScriptElement>(element); } } |