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(); } }
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); }
bool WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, RefPtrWillBeRawPtr<ErrorEvent>* errorEvent, CachedMetadataHandler* cacheHandler, V8CacheOptions v8CacheOptions) { if (isExecutionForbidden()) return false; WorkerGlobalScopeExecutionState state(this); evaluate(sourceCode.source(), sourceCode.url().string(), sourceCode.startPosition(), cacheHandler, v8CacheOptions); if (isExecutionForbidden()) return false; if (state.hadException) { if (errorEvent) { if (state.m_errorEventFromImportedScript) { // Propagate inner error event outwards. *errorEvent = state.m_errorEventFromImportedScript.release(); return false; } if (m_workerGlobalScope.shouldSanitizeScriptError(state.sourceURL, NotSharableCrossOrigin)) *errorEvent = ErrorEvent::createSanitizedError(m_world.get()); else *errorEvent = ErrorEvent::create(state.errorMessage, state.sourceURL, state.lineNumber, state.columnNumber, m_world.get()); V8ErrorHandler::storeExceptionOnErrorEventWrapper(isolate(), errorEvent->get(), state.exception.v8Value(), m_scriptState->context()->Global()); } else { ASSERT(!m_workerGlobalScope.shouldSanitizeScriptError(state.sourceURL, NotSharableCrossOrigin)); RefPtrWillBeRawPtr<ErrorEvent> event = nullptr; if (state.m_errorEventFromImportedScript) event = state.m_errorEventFromImportedScript.release(); else event = ErrorEvent::create(state.errorMessage, state.sourceURL, state.lineNumber, state.columnNumber, m_world.get()); m_workerGlobalScope.reportException(event, 0, nullptr, NotSharableCrossOrigin); } return false; } return true; }
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; }
// Evaluate a script file in the environment of this proxy. ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) { String sourceURL = sourceCode.url(); if (!m_XSSAuditor->canEvaluate(sourceCode.source())) { // This script is not safe to be evaluated. return ScriptValue(); } v8::HandleScope handleScope; // SAMSUNG CHANGE >> if (!m_proxy) return ScriptValue(); // SAMSUNG CHANGE << v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(m_proxy->frame()); if (v8Context.IsEmpty()) return ScriptValue(); v8::Context::Scope scope(v8Context); RefPtr<Frame> protect(m_frame); v8::Local<v8::Value> object = m_proxy->evaluate(sourceCode, 0); // Evaluating the JavaScript could cause the frame to be deallocated // so we starot the keep alive timer here. m_frame->keepAlive(); if (object.IsEmpty() || object->IsUndefined()) return ScriptValue(); return ScriptValue(object); }
v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node) { ASSERT(v8::Context::InContext()); 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); // Compile the script. v8::Local<v8::String> code = v8ExternalString(source.source()); ChromiumBridge::traceEventBegin("v8.compile", node, ""); // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at // 1, whereas v8 starts at 0. v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startLine() - 1); ChromiumBridge::traceEventEnd("v8.compile", node, ""); ChromiumBridge::traceEventBegin("v8.run", node, ""); // Set inlineCode to true for <a href="javascript:doSomething()"> // and false for <script>doSomething</script>. We make a rough guess at // this based on whether the script source has a URL. result = runScript(script, source.url().string().isNull()); } ChromiumBridge::traceEventEnd("v8.run", node, ""); return result; }
ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld* world, ShouldAllowXSS shouldAllowXSS) { const SourceCode& jsSourceCode = sourceCode.jsSourceCode(); String sourceURL = ustringToString(jsSourceCode.provider()->url()); if (shouldAllowXSS == DoNotAllowXSS && !m_XSSAuditor->canEvaluate(sourceCode.source())) { // This script is not safe to be evaluated. return JSValue(); } // evaluate code. Returns the JS return value or 0 // if there was none, an error occurred or the type couldn't be converted. // inlineCode is true for <a href="javascript:doSomething()"> // and false for <script>doSomething()</script>. Check if it has the // expected value in all cases. // See smart window.open policy for where this is used. JSDOMWindowShell* shell = windowShell(world); ExecState* exec = shell->window()->globalExec(); const String* savedSourceURL = m_sourceURL; m_sourceURL = &sourceURL; JSLock lock(SilenceAssertionsOnly); RefPtr<Frame> protect = m_frame; #if ENABLE(INSPECTOR) if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0) timelineAgent->willEvaluateScript(sourceURL, sourceCode.startLine()); #endif exec->globalData().timeoutChecker.start(); Completion comp = JSMainThreadExecState::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), jsSourceCode, shell); exec->globalData().timeoutChecker.stop(); #if ENABLE(INSPECTOR) if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0) timelineAgent->didEvaluateScript(); #endif // Evaluating the JavaScript could cause the frame to be deallocated // so we start the keep alive timer here. m_frame->keepAlive(); if (comp.complType() == Normal || comp.complType() == ReturnValue) { m_sourceURL = savedSourceURL; return comp.value(); } if (comp.complType() == Throw || comp.complType() == Interrupted) reportException(exec, comp.value()); m_sourceURL = savedSourceURL; return JSValue(); }
ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) { { MutexLocker lock(m_sharedDataMutex); if (m_executionForbidden) return ScriptValue(); } v8::Local<v8::Value> result = m_proxy->evaluate(sourceCode.source(), sourceCode.url().string(), sourceCode.startLine() - 1); m_workerContext->thread()->workerObjectProxy().reportPendingActivity(m_workerContext->hasPendingActivity()); return ScriptValue(); }
v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node) { ASSERT(v8::Context::InContext()); V8GCController::checkMemoryUsage(); #if ENABLE(INSPECTOR) if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0) timelineAgent->willEvaluateScript(source.url().isNull() ? String() : source.url().string(), source.startLine()); #endif 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); // Compile the script. v8::Local<v8::String> code = v8ExternalString(source.source()); #if PLATFORM(CHROMIUM) PlatformBridge::traceEventBegin("v8.compile", node, ""); #endif OwnPtr<v8::ScriptData> scriptData = precompileScript(code, source.cachedScript()); // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at // 1, whereas v8 starts at 0. v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startLine() - 1, scriptData.get()); #if PLATFORM(CHROMIUM) PlatformBridge::traceEventEnd("v8.compile", node, ""); PlatformBridge::traceEventBegin("v8.run", node, ""); #endif // Set inlineCode to true for <a href="javascript:doSomething()"> // and false for <script>doSomething</script>. We make a rough guess at // this based on whether the script source has a URL. result = runScript(script, source.url().string().isNull()); } #if PLATFORM(CHROMIUM) PlatformBridge::traceEventEnd("v8.run", node, ""); #endif #if ENABLE(INSPECTOR) if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0) timelineAgent->didEvaluateScript(); #endif return result; }
void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, ScriptValue* exception) { if (isExecutionForbidden()) return; WorkerContextExecutionState state; m_proxy->evaluate(sourceCode.source(), sourceCode.url().string(), sourceCode.startPosition(), &state); if (state.hadException) { if (exception) *exception = state.exception; else m_workerContext->reportException(state.errorMessage, state.lineNumber, state.sourceURL, 0); } }
bool WorkerOrWorkletScriptController::evaluate( const ScriptSourceCode& sourceCode, ErrorEvent** errorEvent, CachedMetadataHandler* cacheHandler, V8CacheOptions v8CacheOptions) { if (isExecutionForbidden()) return false; ExecutionState state(this); evaluate(sourceCode.source(), sourceCode.url().getString(), sourceCode.startPosition(), cacheHandler, v8CacheOptions); if (isExecutionForbidden()) return false; if (state.hadException) { if (errorEvent) { if (state.m_errorEventFromImportedScript) { // Propagate inner error event outwards. *errorEvent = state.m_errorEventFromImportedScript.release(); return false; } if (m_globalScope->shouldSanitizeScriptError(state.m_location->url(), NotSharableCrossOrigin)) *errorEvent = ErrorEvent::createSanitizedError(m_world.get()); else *errorEvent = ErrorEvent::create( state.errorMessage, state.m_location->clone(), m_world.get()); V8ErrorHandler::storeExceptionOnErrorEventWrapper( m_scriptState.get(), *errorEvent, state.exception.v8Value(), m_scriptState->context()->Global()); } else { DCHECK(!m_globalScope->shouldSanitizeScriptError(state.m_location->url(), NotSharableCrossOrigin)); ErrorEvent* event = nullptr; if (state.m_errorEventFromImportedScript) event = state.m_errorEventFromImportedScript.release(); else event = ErrorEvent::create(state.errorMessage, state.m_location->clone(), m_world.get()); m_globalScope->dispatchErrorEvent(event, NotSharableCrossOrigin); } return false; } return true; }
void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, RefPtr<ErrorEvent>* errorEvent) { if (isExecutionForbidden()) return; WorkerGlobalScopeExecutionState state; evaluate(sourceCode.source(), sourceCode.url().string(), sourceCode.startPosition(), &state); if (state.hadException) { if (errorEvent) { *errorEvent = m_workerGlobalScope.shouldSanitizeScriptError(state.sourceURL, NotSharableCrossOrigin) ? ErrorEvent::createSanitizedError(nullptr) : ErrorEvent::create(state.errorMessage, state.sourceURL, state.lineNumber, state.columnNumber, nullptr); V8ErrorHandler::storeExceptionOnErrorEventWrapper(errorEvent->get(), state.exception.v8Value(), isolate()); } else { ASSERT(!m_workerGlobalScope.shouldSanitizeScriptError(state.sourceURL, NotSharableCrossOrigin)); RefPtr<ErrorEvent> event = m_errorEventFromImportedScript ? m_errorEventFromImportedScript.release() : ErrorEvent::create(state.errorMessage, state.sourceURL, state.lineNumber, state.columnNumber, nullptr); m_workerGlobalScope.reportException(event, nullptr, NotSharableCrossOrigin); } } }
v8::Local<v8::Value> ScriptController::compileAndRunScript(const ScriptSourceCode& source) { ASSERT(v8::Context::InContext()); V8GCController::checkMemoryUsage(); 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); // Compile the script. v8::Local<v8::String> code = v8ExternalString(source.source()); #if PLATFORM(CHROMIUM) TRACE_EVENT_BEGIN0("v8", "v8.compile"); #endif OwnPtr<v8::ScriptData> scriptData = ScriptSourceCode::precompileScript(code, source.cachedScript()); // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at // 1, whereas v8 starts at 0. v8::Handle<v8::Script> script = ScriptSourceCode::compileScript(code, source.url(), source.startPosition(), scriptData.get()); #if PLATFORM(CHROMIUM) TRACE_EVENT_END0("v8", "v8.compile"); TRACE_EVENT0("v8", "v8.run"); #endif // Keep Frame (and therefore ScriptController) alive. RefPtr<Frame> protect(m_frame); result = ScriptRunner::runCompiledScript(script, m_frame->document()); ASSERT(!tryCatch.HasCaught() || result.IsEmpty()); } InspectorInstrumentation::didEvaluateScript(cookie); return result; }
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; }
void ScriptElement::executeScript(const ScriptSourceCode& sourceCode) { ASSERT(m_alreadyStarted); if (sourceCode.isEmpty()) 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; } Ref<Document> document(m_element.document()); if (Frame* frame = document->frame()) { IgnoreDestructiveWriteCountIncrementer ignoreDesctructiveWriteCountIncrementer(m_isExternalScript ? document.ptr() : nullptr); CurrentScriptIncrementer currentScriptIncrementer(document, 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); } }
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); }