bool SubresourceIntegrity::CheckSubresourceIntegrity(const IntegrityMetadataSet& metadataSet, const char* content, size_t size, const KURL& resourceUrl, Document& document, String& errorMessage)
{
    if (!metadataSet.size())
        return true;

    HashAlgorithm strongestAlgorithm = HashAlgorithmSha256;
    for (const IntegrityMetadata& metadata : metadataSet)
        strongestAlgorithm = getPrioritizedHashFunction(metadata.algorithm(), strongestAlgorithm);

    DigestValue digest;
    for (const IntegrityMetadata& metadata : metadataSet) {
        if (metadata.algorithm() != strongestAlgorithm)
            continue;

        digest.clear();
        bool digestSuccess = computeDigest(metadata.algorithm(), content, size, digest);

        if (digestSuccess) {
            Vector<char> hashVector;
            base64Decode(metadata.digest(), hashVector);
            DigestValue convertedHashVector;
            convertedHashVector.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size());

            if (DigestsEqual(digest, convertedHashVector)) {
                UseCounter::count(document, UseCounter::SRIElementWithMatchingIntegrityAttribute);
                return true;
            }
        }
    }

    digest.clear();
    if (computeDigest(HashAlgorithmSha256, content, size, digest)) {
        // This message exposes the digest of the resource to the console.
        // Because this is only to the console, that's okay for now, but we
        // need to be very careful not to expose this in exceptions or
        // JavaScript, otherwise it risks exposing information about the
        // resource cross-origin.
        errorMessage = "Failed to find a valid digest in the 'integrity' attribute for resource '" + resourceUrl.elidedString() + "' with computed SHA-256 integrity '" + digestToString(digest) + "'. The resource has been blocked.";
    } else {
        errorMessage = "There was an error computing an integrity value for resource '" + resourceUrl.elidedString() + "'. The resource has been blocked.";
    }
    UseCounter::count(document, UseCounter::SRIElementWithNonMatchingIntegrityAttribute);
    return false;
}
PassOwnPtr<DOMPatchSupport::Digest> DOMPatchSupport::createDigest(Node* node, UnusedNodesMap* unusedNodesMap)
{
    Digest* digest = new Digest(node);

    OwnPtr<blink::WebCryptoDigestor> digestor = createDigestor(HashAlgorithmSha1);
    DigestValue digestResult;

    Node::NodeType nodeType = node->nodeType();
    digestor->consume(reinterpret_cast<const unsigned char*>(&nodeType), sizeof(nodeType));
    addStringToDigestor(digestor.get(), node->nodeName());
    addStringToDigestor(digestor.get(), node->nodeValue());

    if (node->isElementNode()) {
        Element& element = toElement(*node);
        Node* child = element.firstChild();
        while (child) {
            OwnPtr<Digest> childInfo = createDigest(child, unusedNodesMap);
            addStringToDigestor(digestor.get(), childInfo->m_sha1);
            child = child->nextSibling();
            digest->m_children.append(childInfo.release());
        }

        if (element.hasAttributesWithoutUpdate()) {
            OwnPtr<blink::WebCryptoDigestor> attrsDigestor = createDigestor(HashAlgorithmSha1);
            AttributeCollection attributes = element.attributes();
            AttributeCollection::const_iterator end = attributes.end();
            for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) {
                addStringToDigestor(attrsDigestor.get(), it->name().toString());
                addStringToDigestor(attrsDigestor.get(), it->value().string());
            }
            finishDigestor(attrsDigestor.get(), digestResult);
            digest->m_attrsSHA1 = base64Encode(reinterpret_cast<const char*>(digestResult.data()), 10);
            addStringToDigestor(digestor.get(), digest->m_attrsSHA1);
            digestResult.clear();
        }
    }
    finishDigestor(digestor.get(), digestResult);
    digest->m_sha1 = base64Encode(reinterpret_cast<const char*>(digestResult.data()), 10);

    if (unusedNodesMap)
        unusedNodesMap->add(digest->m_sha1, digest);
    return adoptPtr(digest);
}