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; }
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; }
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(); } } }