void ScriptLoader::executeScript(const ScriptSourceCode& sourceCode, double* compilationFinishTime) { ASSERT(m_alreadyStarted); if (sourceCode.isEmpty()) return; RefPtrWillBeRawPtr<Document> elementDocument(m_element->document()); RefPtrWillBeRawPtr<Document> contextDocument = elementDocument->contextDocument().get(); if (!contextDocument) return; LocalFrame* frame = contextDocument->frame(); const ContentSecurityPolicy* csp = elementDocument->contentSecurityPolicy(); bool shouldBypassMainWorldCSP = (frame && frame->script().shouldBypassMainWorldCSP()) || csp->allowScriptWithNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr)) || csp->allowScriptWithHash(sourceCode.source()); if (!m_isExternalScript && (!shouldBypassMainWorldCSP && !csp->allowInlineScript(elementDocument->url(), m_startLineNumber))) return; if (m_isExternalScript) { ScriptResource* resource = m_resource ? m_resource.get() : sourceCode.resource(); if (resource && !resource->mimeTypeAllowedByNosniff()) { contextDocument->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + resource->mimeType() + "') is not executable, and strict MIME type checking is enabled.")); return; } if (!SubresourceIntegrity::CheckSubresourceIntegrity(*m_element, sourceCode.source(), sourceCode.resource()->url(), sourceCode.resource()->mimeType())) return; } // FIXME: Can this be moved earlier in the function? // Why are we ever attempting to execute scripts without a frame? if (!frame) return; const bool isImportedScript = contextDocument != elementDocument; // http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block step 2.3 // with additional support for HTML imports. IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_isExternalScript || isImportedScript ? contextDocument.get() : 0); if (isHTMLScriptLoader(m_element)) contextDocument->pushCurrentScript(toHTMLScriptElement(m_element)); AccessControlStatus corsCheck = NotSharableCrossOrigin; if (!m_isExternalScript || (sourceCode.resource() && sourceCode.resource()->passesAccessControlCheck(&m_element->document(), m_element->document().securityOrigin()))) corsCheck = SharableCrossOrigin; // 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().executeScriptInMainWorld(sourceCode, corsCheck, compilationFinishTime); if (isHTMLScriptLoader(m_element)) { ASSERT(contextDocument->currentScript() == m_element); contextDocument->popCurrentScript(); } }
bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) { DCHECK(m_alreadyStarted); if (sourceCode.isEmpty()) return true; Document* elementDocument = &(m_element->document()); Document* contextDocument = elementDocument->contextDocument(); if (!contextDocument) return true; LocalFrame* frame = contextDocument->frame(); const ContentSecurityPolicy* csp = elementDocument->contentSecurityPolicy(); bool shouldBypassMainWorldCSP = (frame && frame->script().shouldBypassMainWorldCSP()) || csp->allowScriptWithHash(sourceCode.source(), ContentSecurityPolicy::InlineType::Block); AtomicString nonce = ContentSecurityPolicy::isNonceableElement(m_element.get()) ? m_element->fastGetAttribute(HTMLNames::nonceAttr) : AtomicString(); if (!m_isExternalScript && (!shouldBypassMainWorldCSP && !csp->allowInlineScript(m_element, elementDocument->url(), nonce, m_startLineNumber, sourceCode.source()))) { return false; } if (m_isExternalScript) { ScriptResource* resource = m_resource ? m_resource.get() : sourceCode.resource(); if (resource) { if (!resource->mimeTypeAllowedByNosniff()) { contextDocument->addConsoleMessage(ConsoleMessage::create( SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + resource->httpContentType() + "') is not executable, and " "strict MIME type checking is " "enabled.")); return false; } String mimeType = resource->httpContentType(); if (mimeType.startsWith("image/") || mimeType == "text/csv" || mimeType.startsWith("audio/") || mimeType.startsWith("video/")) { contextDocument->addConsoleMessage(ConsoleMessage::create( SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + mimeType + "') is not executable.")); if (mimeType.startsWith("image/")) UseCounter::count(frame, UseCounter::BlockedSniffingImageToScript); else if (mimeType.startsWith("audio/")) UseCounter::count(frame, UseCounter::BlockedSniffingAudioToScript); else if (mimeType.startsWith("video/")) UseCounter::count(frame, UseCounter::BlockedSniffingVideoToScript); else if (mimeType == "text/csv") UseCounter::count(frame, UseCounter::BlockedSniffingCSVToScript); return false; } logScriptMIMEType(frame, resource, mimeType); } } // FIXME: Can this be moved earlier in the function? // Why are we ever attempting to execute scripts without a frame? if (!frame) return true; AccessControlStatus accessControlStatus = NotSharableCrossOrigin; if (!m_isExternalScript) { accessControlStatus = SharableCrossOrigin; } else if (sourceCode.resource()) { if (sourceCode.resource()->response().wasFetchedViaServiceWorker()) { if (sourceCode.resource()->response().serviceWorkerResponseType() == WebServiceWorkerResponseTypeOpaque) accessControlStatus = OpaqueResource; else accessControlStatus = SharableCrossOrigin; } else if (sourceCode.resource()->passesAccessControlCheck( m_element->document().getSecurityOrigin())) { accessControlStatus = SharableCrossOrigin; } } const bool isImportedScript = contextDocument != elementDocument; // http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block // step 2.3 with additional support for HTML imports. IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer( m_isExternalScript || isImportedScript ? contextDocument : 0); if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element)) contextDocument->pushCurrentScript(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().executeScriptInMainWorld(sourceCode, accessControlStatus); if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element)) { DCHECK(contextDocument->currentScript() == m_element); contextDocument->popCurrentScript(); } return true; }