예제 #1
0
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();
    }
}
예제 #2
0
v8::Local<v8::Value> ScriptController::executeScriptAndReturnValue(v8::Handle<v8::Context> context, const ScriptSourceCode& source, AccessControlStatus corsStatus)
{
    v8::Context::Scope scope(context);

    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, source.url().isNull() ? String() : source.url().string(), source.startLine());

    v8::Local<v8::Value> result;
    {
        // Isolate exceptions that occur when compiling and executing
        // the code. These exceptions should not interfere with
        // javascript code we might evaluate from C++ when returning
        // from here.
        v8::TryCatch tryCatch;
        tryCatch.SetVerbose(true);

        v8::Handle<v8::String> code = v8String(m_isolate, source.source());
        OwnPtr<v8::ScriptData> scriptData = V8ScriptRunner::precompileScript(code, source.resource());

        // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
        // 1, whereas v8 starts at 0.
        v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(code, source.url(), source.startPosition(), scriptData.get(), m_isolate, corsStatus);

        // Keep LocalFrame (and therefore ScriptController) alive.
        RefPtr<LocalFrame> protect(m_frame);
        result = V8ScriptRunner::runCompiledScript(script, m_frame->document(), m_isolate);
        ASSERT(!tryCatch.HasCaught() || result.IsEmpty());
    }

    InspectorInstrumentation::didEvaluateScript(cookie);

    return result;
}
v8::Local<v8::Value> ScriptController::executeScriptAndReturnValue(v8::Local<v8::Context> context, const ScriptSourceCode& source, AccessControlStatus accessControlStatus, double* compilationFinishTime)
{
    TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data", InspectorEvaluateScriptEvent::data(frame(), source.url().getString(), source.startPosition()));
    InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(frame()->document(), "scriptFirstStatement", false);

    v8::Local<v8::Value> result;
    {
        V8CacheOptions v8CacheOptions(V8CacheOptionsDefault);
        if (frame()->settings())
            v8CacheOptions = frame()->settings()->v8CacheOptions();
        if (source.resource() && !source.resource()->response().cacheStorageCacheName().isNull()) {
            switch (frame()->settings()->v8CacheStrategiesForCacheStorage()) {
            case V8CacheStrategiesForCacheStorage::None:
                v8CacheOptions = V8CacheOptionsNone;
                break;
            case V8CacheStrategiesForCacheStorage::Normal:
                v8CacheOptions = V8CacheOptionsCode;
                break;
            case V8CacheStrategiesForCacheStorage::Default:
            case V8CacheStrategiesForCacheStorage::Aggressive:
                v8CacheOptions = V8CacheOptionsAlways;
                break;
            }
        }

        // Isolate exceptions that occur when compiling and executing
        // the code. These exceptions should not interfere with
        // javascript code we might evaluate from C++ when returning
        // from here.
        v8::TryCatch tryCatch(isolate());
        tryCatch.SetVerbose(true);

        v8::Local<v8::Script> script;
        if (!v8Call(V8ScriptRunner::compileScript(source, isolate(), accessControlStatus, v8CacheOptions), script, tryCatch))
            return result;

        if (compilationFinishTime) {
            *compilationFinishTime = WTF::monotonicallyIncreasingTime();
        }
        if (!v8Call(V8ScriptRunner::runCompiledScript(isolate(), script, frame()->document()), result, tryCatch))
            return result;
    }

    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data());

    return result;
}
예제 #4
0
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;
}
예제 #5
0
v8::Local<v8::Script> V8ScriptRunner::compileScript(const ScriptSourceCode& source, v8::Isolate* isolate, AccessControlStatus corsStatus)
{
    return compileScript(v8String(isolate, source.source()), source.url(), source.startPosition(), source.resource(), isolate, corsStatus);
}
예제 #6
0
v8::MaybeLocal<v8::Script> V8ScriptRunner::compileScript(const ScriptSourceCode& source, v8::Isolate* isolate, AccessControlStatus corsStatus, V8CacheOptions cacheOptions)
{
    if (source.source().length() >= v8::String::kMaxLength) {
        V8ThrowException::throwGeneralError(isolate, "Source file too large.");
        return v8::Local<v8::Script>();
    }
    return compileScript(v8String(isolate, source.source()), source.url(), source.sourceMapUrl(), source.startPosition(), isolate, source.resource(), source.streamer(), source.resource() ? source.resource()->cacheHandler() : nullptr, corsStatus, cacheOptions);
}