void SVGExternalResourcesRequired::insertedIntoDocument(SVGElement* targetElement)
{
    if (isParserInserted())
        return;

    // Eventually send SVGLoad event now for the dynamically inserted script element.
    if (externalResourcesRequiredBaseValue())
        return;
    setHaveFiredLoadEvent(true);
    targetElement->sendSVGLoadEventIfPossible();
}
bool ScriptLoader::fetchScript(const String& sourceUrl, FetchRequest::DeferOption defer)
{
    DCHECK(m_element);

    Document* elementDocument = &(m_element->document());
    if (!m_element->inShadowIncludingDocument() || m_element->document() != elementDocument)
        return false;

    DCHECK(!m_resource);
    if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) {
        FetchRequest request(ResourceRequest(elementDocument->completeURL(sourceUrl)), m_element->localName());

        CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue(m_element->fastGetAttribute(HTMLNames::crossoriginAttr));
        if (crossOrigin != CrossOriginAttributeNotSet)
            request.setCrossOriginAccessControl(elementDocument->getSecurityOrigin(), crossOrigin);
        request.setCharset(scriptCharset());

        // Skip fetch-related CSP checks if dynamically injected script is whitelisted and this script is not parser-inserted.
        bool scriptPassesCSPDynamic = (!isParserInserted() && elementDocument->contentSecurityPolicy()->allowDynamic());

        request.setContentSecurityPolicyNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr));

        if (scriptPassesCSPDynamic) {
            UseCounter::count(elementDocument->frame(), UseCounter::ScriptPassesCSPDynamic);
            request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy);
        }
        request.setDefer(defer);

        String integrityAttr = m_element->fastGetAttribute(HTMLNames::integrityAttr);
        if (!integrityAttr.isEmpty()) {
            IntegrityMetadataSet metadataSet;
            SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet, elementDocument);
            request.setIntegrityMetadata(metadataSet);
        }

        m_resource = ScriptResource::fetch(request, elementDocument->fetcher());

        m_isExternalScript = true;
    }

    if (m_resource)
        return true;

    dispatchErrorEvent();
    return false;
}
bool SVGExternalResourcesRequired::handleAttributeChange(SVGElement* targetElement, const QualifiedName& attrName)
{
    ASSERT(targetElement);
    if (!isKnownAttribute(attrName))
        return false;
    if (!targetElement->inDocument())
        return true;

    // Handle dynamic updates of the 'externalResourcesRequired' attribute. Only possible case: changing from 'true' to 'false'
    // causes an immediate dispatch of the SVGLoad event. If the attribute value was 'false' before inserting the script element
    // in the document, the SVGLoad event has already been dispatched.
    if (!externalResourcesRequiredBaseValue() && !haveFiredLoadEvent() && !isParserInserted()) {
        setHaveFiredLoadEvent(true);
        ASSERT(targetElement->haveLoadedRequiredResources());

        targetElement->sendSVGLoadEventIfPossible();
    }

    return true;
}
void SVGExternalResourcesRequired::dispatchLoadEvent(SVGElement* targetElement)
{
    bool externalResourcesRequired = externalResourcesRequiredBaseValue();

    if (isParserInserted())
        ASSERT(externalResourcesRequired != haveFiredLoadEvent());
    else if (haveFiredLoadEvent())
        return;

    // HTML and SVG differ completely in the 'onload' event handling of <script> elements.
    // HTML fires the 'load' event after it sucessfully loaded a remote resource, otherwise an error event.
    // SVG fires the SVGLoad event immediately after parsing the <script> element, if externalResourcesRequired
    // is set to 'false', otherwise it dispatches the 'SVGLoad' event just after loading the remote resource.
    if (!externalResourcesRequired)
        return;

    ASSERT(!haveFiredLoadEvent());

    // Dispatch SVGLoad event
    setHaveFiredLoadEvent(true);
    ASSERT(targetElement->haveLoadedRequiredResources());

    targetElement->sendSVGLoadEventIfPossible();
}
Beispiel #5
0
bool ScriptLoader::fetchScript(const String& sourceUrl,
                               FetchRequest::DeferOption defer) {
    DCHECK(m_element);

    Document* elementDocument = &(m_element->document());
    if (!m_element->isConnected() || m_element->document() != elementDocument)
        return false;

    DCHECK(!m_resource);
    if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) {
        FetchRequest request(
            ResourceRequest(elementDocument->completeURL(sourceUrl)),
            m_element->localName());

        CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue(
                m_element->fastGetAttribute(HTMLNames::crossoriginAttr));
        if (crossOrigin != CrossOriginAttributeNotSet)
            request.setCrossOriginAccessControl(elementDocument->getSecurityOrigin(),
                                                crossOrigin);
        request.setCharset(scriptCharset());

        if (ContentSecurityPolicy::isNonceableElement(m_element.get())) {
            request.setContentSecurityPolicyNonce(
                m_element->fastGetAttribute(HTMLNames::nonceAttr));
        }

        request.setParserDisposition(isParserInserted() ? ParserInserted
                                     : NotParserInserted);

        request.setDefer(defer);

        String integrityAttr =
            m_element->fastGetAttribute(HTMLNames::integrityAttr);
        if (!integrityAttr.isEmpty()) {
            IntegrityMetadataSet metadataSet;
            SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet,
                    elementDocument);
            request.setIntegrityMetadata(metadataSet);
        }

        if (m_documentWriteIntervention ==
                DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) {
            request.mutableResourceRequest().setHTTPHeaderField(
                "Intervention",
                "<https://www.chromestatus.com/feature/5718547946799104>");
        }

        m_resource = ScriptResource::fetch(request, elementDocument->fetcher());

        m_isExternalScript = true;
    }

    if (!m_resource) {
        dispatchErrorEvent();
        return false;
    }

    if (m_createdDuringDocumentWrite &&
            m_resource->resourceRequest().getCachePolicy() ==
            WebCachePolicy::ReturnCacheDataDontLoad) {
        m_documentWriteIntervention =
            DocumentWriteIntervention::DoNotFetchDocWrittenScript;
    }

    return true;
}
bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode, double* compilationFinishTime)
{
    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().toString(), ContentSecurityPolicy::InlineType::Block)
        || (!isParserInserted() && csp->allowDynamic());

    if (!m_isExternalScript && (!shouldBypassMainWorldCSP && !csp->allowInlineScript(elementDocument->url(), m_element->fastGetAttribute(HTMLNames::nonceAttr), m_startLineNumber, sourceCode.source().toString()))) {
        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/")) {
                contextDocument->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + mimetype + "') is not executable."));
                UseCounter::count(frame, UseCounter::BlockedSniffingImageToScript);
                return false;
            }

            logScriptMimetype(resource, frame, 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, compilationFinishTime);

    if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element)) {
        DCHECK(contextDocument->currentScript() == m_element);
        contextDocument->popCurrentScript();
    }

    return true;
}