Exemplo n.º 1
0
bool ScriptStreamer::startStreamingInternal(PendingScript& script, Settings* settings, ScriptState* scriptState, PendingScript::Type scriptType)
{
    ASSERT(isMainThread());
    if (!settings || !settings->v8ScriptStreamingEnabled())
        return false;
    if (settings->v8ScriptStreamingMode() == ScriptStreamingModeOnlyAsyncAndDefer
        && scriptType == PendingScript::ParsingBlocking)
        return false;

    ScriptResource* resource = script.resource();
    if (resource->isLoaded())
        return false;
    if (!resource->url().protocolIsInHTTPFamily())
        return false;
    if (resource->resourceToRevalidate()) {
        // This happens e.g., during reloads. We're actually not going to load
        // the current Resource of the PendingScript but switch to another
        // Resource -> don't stream.
        return false;
    }
    // We cannot filter out short scripts, even if we wait for the HTTP headers
    // to arrive. In general, the web servers don't seem to send the
    // Content-Length HTTP header for scripts.

    if (!scriptState->contextIsValid())
        return false;

    // Decide what kind of cached data we should produce while streaming. By
    // default, we generate the parser cache for streamed scripts, to emulate
    // the non-streaming behavior (see V8ScriptRunner::compileScript).
    v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProduceParserCache;
    if (settings->v8CacheOptions() == V8CacheOptionsCode)
        compileOption = v8::ScriptCompiler::kProduceCodeCache;

    // The Resource might go out of scope if the script is no longer
    // needed. This makes PendingScript notify the ScriptStreamer when it is
    // destroyed.
    script.setStreamer(adoptRef(new ScriptStreamer(resource, scriptType, settings->v8ScriptStreamingMode(), scriptState, compileOption)));

    return true;
}
Exemplo n.º 2
0
bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode, double* compilationFinishTime)
{
    ASSERT(m_alreadyStarted);

    if (sourceCode.isEmpty())
        return true;

    RefPtrWillBeRawPtr<Document> elementDocument(m_element->document());
    RefPtrWillBeRawPtr<Document> contextDocument = elementDocument->contextDocument().get();
    if (!contextDocument)
        return true;

    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, sourceCode.source()))) {
        return false;
    }

    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 false;
        }

        if (resource && resource->mimeType().lower().startsWith("image/")) {
            contextDocument->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + resource->mimeType() + "') is not executable."));
            UseCounter::count(frame, UseCounter::BlockedSniffingImageToScript);
            return false;
        }
    }

    // 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().securityOrigin())) {
            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.get() : 0);

    if (isHTMLScriptLoader(m_element))
        contextDocument->pushCurrentScript(toHTMLScriptElement(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)) {
        ASSERT(contextDocument->currentScript() == m_element);
        contextDocument->popCurrentScript();
    }

    return true;
}
Exemplo n.º 3
0
void ScriptLoader::executeScript(const ScriptSourceCode& sourceCode)
{
    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();

    bool shouldBypassMainWorldContentSecurityPolicy = (frame && frame->script().shouldBypassMainWorldContentSecurityPolicy()) || elementDocument->contentSecurityPolicy()->allowScriptNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr)) || elementDocument->contentSecurityPolicy()->allowScriptHash(sourceCode.source());

    if (!m_isExternalScript && (!shouldBypassMainWorldContentSecurityPolicy && !elementDocument->contentSecurityPolicy()->allowInlineScript(elementDocument->url(), m_startLineNumber)))
        return;

    if (m_isExternalScript) {
        ScriptResource* resource = m_resource ? m_resource.get() : sourceCode.resource();
        if (resource && !resource->mimeTypeAllowedByNosniff()) {
            contextDocument->addConsoleMessage(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 (frame) {
        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().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);

        if (isHTMLScriptLoader(m_element)) {
            ASSERT(contextDocument->currentScript() == m_element);
            contextDocument->popCurrentScript();
        }
    }
}