blob: 8fa81d109a4c73cd0b3195b88ff5e3db157c38e6 [file] [log] [blame]
/*
* Copyright (C) 2014-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "NetworkCacheKey.h"
#include "NetworkCacheCoders.h"
#include <wtf/ASCIICType.h>
#include <wtf/persistence/PersistentDecoder.h>
#include <wtf/persistence/PersistentEncoder.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>
namespace WebKit {
namespace NetworkCache {
Key::Key(const Key& o)
: m_partition(o.m_partition.isolatedCopy())
, m_type(o.m_type.isolatedCopy())
, m_identifier(o.m_identifier.isolatedCopy())
, m_range(o.m_range.isolatedCopy())
, m_hash(o.m_hash)
, m_partitionHash(o.m_partitionHash)
{
}
Key::Key(const String& partition, const String& type, const String& range, const String& identifier, const Salt& salt)
: m_partition(partition)
, m_type(type)
, m_identifier(identifier)
, m_range(range)
, m_hash(computeHash(salt))
, m_partitionHash(computePartitionHash(salt))
{
}
Key::Key(WTF::HashTableDeletedValueType)
: m_identifier(WTF::HashTableDeletedValue)
{
}
Key::Key(const DataKey& dataKey, const Salt& salt)
: m_partition(dataKey.partition)
, m_type(dataKey.type)
, m_identifier(hashAsString(dataKey.identifier))
, m_hash(computeHash(salt))
, m_partitionHash(computePartitionHash(salt))
{
}
Key& Key::operator=(const Key& other)
{
m_partition = other.m_partition.isolatedCopy();
m_type = other.m_type.isolatedCopy();
m_identifier = other.m_identifier.isolatedCopy();
m_range = other.m_range.isolatedCopy();
m_hash = other.m_hash;
m_partitionHash = other.m_partitionHash;
return *this;
}
static void hashString(SHA1& sha1, const String& string)
{
if (string.isNull())
return;
if (string.is8Bit() && string.isAllASCII()) {
const uint8_t nullByte = 0;
sha1.addBytes(string.characters8(), string.length());
sha1.addBytes(&nullByte, 1);
return;
}
auto cString = string.utf8();
// Include terminating null byte.
sha1.addBytes(reinterpret_cast<const uint8_t*>(cString.data()), cString.length() + 1);
}
Key::HashType Key::computeHash(const Salt& salt) const
{
// We don't really need a cryptographic hash. The key is always verified against the entry header.
// SHA1 just happens to be suitably sized, fast and available.
SHA1 sha1;
sha1.addBytes(salt.data(), salt.size());
hashString(sha1, m_partition);
hashString(sha1, m_type);
hashString(sha1, m_identifier);
hashString(sha1, m_range);
SHA1::Digest hash;
sha1.computeHash(hash);
return hash;
}
Key::HashType Key::computePartitionHash(const Salt& salt) const
{
SHA1 sha1;
sha1.addBytes(salt.data(), salt.size());
hashString(sha1, m_partition);
SHA1::Digest hash;
sha1.computeHash(hash);
return hash;
}
String Key::hashAsString(const HashType& hash)
{
StringBuilder builder;
builder.reserveCapacity(hashStringLength());
for (auto byte : hash) {
builder.append(upperNibbleToASCIIHexDigit(byte));
builder.append(lowerNibbleToASCIIHexDigit(byte));
}
return builder.toString();
}
template <typename CharType> bool hexDigitsToHash(CharType* characters, Key::HashType& hash)
{
for (unsigned i = 0; i < sizeof(hash); ++i) {
auto high = characters[2 * i];
auto low = characters[2 * i + 1];
if (!isASCIIHexDigit(high) || !isASCIIHexDigit(low))
return false;
hash[i] = toASCIIHexValue(high, low);
}
return true;
}
bool Key::stringToHash(const String& string, HashType& hash)
{
if (string.length() != hashStringLength())
return false;
if (string.is8Bit())
return hexDigitsToHash(string.characters8(), hash);
return hexDigitsToHash(string.characters16(), hash);
}
bool Key::operator==(const Key& other) const
{
return m_hash == other.m_hash && m_partition == other.m_partition && m_type == other.m_type && m_identifier == other.m_identifier && m_range == other.m_range;
}
void Key::encode(WTF::Persistence::Encoder& encoder) const
{
encoder << m_partition;
encoder << m_type;
encoder << m_identifier;
encoder << m_range;
encoder << m_hash;
encoder << m_partitionHash;
}
bool Key::decode(WTF::Persistence::Decoder& decoder, Key& key)
{
return decoder.decode(key.m_partition) && decoder.decode(key.m_type) && decoder.decode(key.m_identifier) && decoder.decode(key.m_range) && decoder.decode(key.m_hash) && decoder.decode(key.m_partitionHash);
}
}
}