1/*
2 * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "NetworkCacheKey.h"
28
29#include "NetworkCacheCoders.h"
30#include <wtf/ASCIICType.h>
31#include <wtf/persistence/PersistentDecoder.h>
32#include <wtf/persistence/PersistentEncoder.h>
33#include <wtf/text/CString.h>
34#include <wtf/text/StringBuilder.h>
35
36namespace WebKit {
37namespace NetworkCache {
38
39Key::Key(const Key& o)
40 : m_partition(o.m_partition.isolatedCopy())
41 , m_type(o.m_type.isolatedCopy())
42 , m_identifier(o.m_identifier.isolatedCopy())
43 , m_range(o.m_range.isolatedCopy())
44 , m_hash(o.m_hash)
45 , m_partitionHash(o.m_partitionHash)
46{
47}
48
49Key::Key(const String& partition, const String& type, const String& range, const String& identifier, const Salt& salt)
50 : m_partition(partition)
51 , m_type(type)
52 , m_identifier(identifier)
53 , m_range(range)
54 , m_hash(computeHash(salt))
55 , m_partitionHash(computePartitionHash(salt))
56{
57}
58
59Key::Key(WTF::HashTableDeletedValueType)
60 : m_identifier(WTF::HashTableDeletedValue)
61{
62}
63
64Key::Key(const DataKey& dataKey, const Salt& salt)
65 : m_partition(dataKey.partition)
66 , m_type(dataKey.type)
67 , m_identifier(hashAsString(dataKey.identifier))
68 , m_hash(computeHash(salt))
69 , m_partitionHash(computePartitionHash(salt))
70{
71}
72
73Key& Key::operator=(const Key& other)
74{
75 m_partition = other.m_partition.isolatedCopy();
76 m_type = other.m_type.isolatedCopy();
77 m_identifier = other.m_identifier.isolatedCopy();
78 m_range = other.m_range.isolatedCopy();
79 m_hash = other.m_hash;
80 m_partitionHash = other.m_partitionHash;
81 return *this;
82}
83
84static void hashString(SHA1& sha1, const String& string)
85{
86 if (string.isNull())
87 return;
88
89 if (string.is8Bit() && string.isAllASCII()) {
90 const uint8_t nullByte = 0;
91 sha1.addBytes(string.characters8(), string.length());
92 sha1.addBytes(&nullByte, 1);
93 return;
94 }
95 auto cString = string.utf8();
96 // Include terminating null byte.
97 sha1.addBytes(reinterpret_cast<const uint8_t*>(cString.data()), cString.length() + 1);
98}
99
100Key::HashType Key::computeHash(const Salt& salt) const
101{
102 // We don't really need a cryptographic hash. The key is always verified against the entry header.
103 // SHA1 just happens to be suitably sized, fast and available.
104 SHA1 sha1;
105 sha1.addBytes(salt.data(), salt.size());
106
107 hashString(sha1, m_partition);
108 hashString(sha1, m_type);
109 hashString(sha1, m_identifier);
110 hashString(sha1, m_range);
111
112 SHA1::Digest hash;
113 sha1.computeHash(hash);
114 return hash;
115}
116
117Key::HashType Key::computePartitionHash(const Salt& salt) const
118{
119 SHA1 sha1;
120 sha1.addBytes(salt.data(), salt.size());
121
122 hashString(sha1, m_partition);
123
124 SHA1::Digest hash;
125 sha1.computeHash(hash);
126 return hash;
127}
128
129String Key::hashAsString(const HashType& hash)
130{
131 StringBuilder builder;
132 builder.reserveCapacity(hashStringLength());
133 for (auto byte : hash) {
134 builder.append(upperNibbleToASCIIHexDigit(byte));
135 builder.append(lowerNibbleToASCIIHexDigit(byte));
136 }
137 return builder.toString();
138}
139
140template <typename CharType> bool hexDigitsToHash(CharType* characters, Key::HashType& hash)
141{
142 for (unsigned i = 0; i < sizeof(hash); ++i) {
143 auto high = characters[2 * i];
144 auto low = characters[2 * i + 1];
145 if (!isASCIIHexDigit(high) || !isASCIIHexDigit(low))
146 return false;
147 hash[i] = toASCIIHexValue(high, low);
148 }
149 return true;
150}
151
152bool Key::stringToHash(const String& string, HashType& hash)
153{
154 if (string.length() != hashStringLength())
155 return false;
156 if (string.is8Bit())
157 return hexDigitsToHash(string.characters8(), hash);
158 return hexDigitsToHash(string.characters16(), hash);
159}
160
161bool Key::operator==(const Key& other) const
162{
163 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;
164}
165
166void Key::encode(WTF::Persistence::Encoder& encoder) const
167{
168 encoder << m_partition;
169 encoder << m_type;
170 encoder << m_identifier;
171 encoder << m_range;
172 encoder << m_hash;
173 encoder << m_partitionHash;
174}
175
176bool Key::decode(WTF::Persistence::Decoder& decoder, Key& key)
177{
178 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);
179}
180
181}
182}
183