예제 #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
void PendingScript::notifyFinished(Resource* resource) {
  // The following SRI checks need to be here because, unfortunately, fetches
  // are not done purely according to the Fetch spec. In particular,
  // different requests for the same resource do not have different
  // responses; the memory cache can (and will) return the exact same
  // Resource object.
  //
  // For different requests, the same Resource object will be returned and
  // will not be associated with the particular request.  Therefore, when the
  // body of the response comes in, there's no way to validate the integrity
  // of the Resource object against a particular request (since there may be
  // several pending requests all tied to the identical object, and the
  // actual requests are not stored).
  //
  // In order to simulate the correct behavior, Blink explicitly does the SRI
  // checks here, when a PendingScript tied to a particular request is
  // finished (and in the case of a StyleSheet, at the point of execution),
  // while having proper Fetch checks in the fetch module for use in the
  // fetch JavaScript API. In a future world where the ResourceFetcher uses
  // the Fetch algorithm, this should be fixed by having separate Response
  // objects (perhaps attached to identical Resource objects) per request.
  //
  // See https://crbug.com/500701 for more information.
  if (m_element) {
    DCHECK_EQ(resource->getType(), Resource::Script);
    ScriptResource* scriptResource = toScriptResource(resource);
    String integrityAttr =
        m_element->fastGetAttribute(HTMLNames::integrityAttr);

    // It is possible to get back a script resource with integrity metadata
    // for a request with an empty integrity attribute. In that case, the
    // integrity check should be skipped, so this check ensures that the
    // integrity attribute isn't empty in addition to checking if the
    // resource has empty integrity metadata.
    if (!integrityAttr.isEmpty() &&
        !scriptResource->integrityMetadata().isEmpty()) {
      ResourceIntegrityDisposition disposition =
          scriptResource->integrityDisposition();
      if (disposition == ResourceIntegrityDisposition::Failed) {
        // TODO(jww): This should probably also generate a console
        // message identical to the one produced by
        // CheckSubresourceIntegrity below. See https://crbug.com/585267.
        m_integrityFailure = true;
      } else if (disposition == ResourceIntegrityDisposition::NotChecked &&
                 resource->resourceBuffer()) {
        m_integrityFailure = !SubresourceIntegrity::CheckSubresourceIntegrity(
            scriptResource->integrityMetadata(), *m_element,
            resource->resourceBuffer()->data(),
            resource->resourceBuffer()->size(), resource->url(), *resource);
        scriptResource->setIntegrityDisposition(
            m_integrityFailure ? ResourceIntegrityDisposition::Failed
                               : ResourceIntegrityDisposition::Passed);
      }
    }
  }

  if (m_streamer)
    m_streamer->notifyFinished(resource);
}
예제 #3
0
ScriptResource* ScriptResource::fetch(FetchRequest& request,
                                      ResourceFetcher* fetcher) {
  DCHECK_EQ(request.resourceRequest().frameType(),
            WebURLRequest::FrameTypeNone);
  request.mutableResourceRequest().setRequestContext(
      WebURLRequest::RequestContextScript);
  ScriptResource* resource = toScriptResource(
      fetcher->requestResource(request, ScriptResourceFactory()));
  if (resource && !request.integrityMetadata().isEmpty())
    resource->setIntegrityMetadata(request.integrityMetadata());
  return resource;
}
예제 #4
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;
}
	MonoArray* ScriptEditorUtility::internal_FindDependencies(MonoObject* resource, bool recursive)
	{
		ScriptResource* srcResource = ScriptResource::toNative(resource);
		if (srcResource == nullptr)
		{
			ScriptArray emptyArray = ScriptArray::create<ScriptResource>(0);
			return emptyArray.getInternal();
		}

		HResource srcHandle = srcResource->getGenericHandle();
		Vector<ResourceDependency> dependencies = Utility::findResourceDependencies(srcHandle, recursive);

		UINT32 numEntries = (UINT32)dependencies.size();
		ScriptArray output = ScriptArray::create<ScriptResource>(numEntries);
		for (UINT32 i = 0; i < numEntries; i++)
		{
			ScriptResourceBase* dependency = ScriptResourceManager::instance().getScriptResource(dependencies[i].resource, true);
			output.set(i, dependency->getManagedInstance());
		}

		return output.getInternal();
	}
예제 #6
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;
}