Improve use of NeverDestroyed
[WebKit-https.git] / Source / WebKit / NetworkProcess / cache / NetworkCacheKey.cpp
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 #if ENABLE(NETWORK_CACHE)
30
31 #include "NetworkCacheCoders.h"
32 #include <wtf/ASCIICType.h>
33 #include <wtf/persistence/Decoder.h>
34 #include <wtf/persistence/Encoder.h>
35 #include <wtf/text/CString.h>
36 #include <wtf/text/StringBuilder.h>
37
38 namespace WebKit {
39 namespace NetworkCache {
40
41 Key::Key(const Key& o)
42     : m_partition(o.m_partition.isolatedCopy())
43     , m_type(o.m_type.isolatedCopy())
44     , m_identifier(o.m_identifier.isolatedCopy())
45     , m_range(o.m_range.isolatedCopy())
46     , m_hash(o.m_hash)
47     , m_partitionHash(o.m_partitionHash)
48 {
49 }
50
51 Key::Key(const String& partition, const String& type, const String& range, const String& identifier, const Salt& salt)
52     : m_partition(partition)
53     , m_type(type)
54     , m_identifier(identifier)
55     , m_range(range)
56     , m_hash(computeHash(salt))
57     , m_partitionHash(computePartitionHash(salt))
58 {
59 }
60
61 Key::Key(WTF::HashTableDeletedValueType)
62     : m_identifier(WTF::HashTableDeletedValue)
63 {
64 }
65
66 Key::Key(const DataKey& dataKey, const Salt& salt)
67     : m_partition(dataKey.partition)
68     , m_type(dataKey.type)
69     , m_identifier(hashAsString(dataKey.identifier))
70     , m_hash(computeHash(salt))
71     , m_partitionHash(computePartitionHash(salt))
72 {
73 }
74
75 Key& Key::operator=(const Key& other)
76 {
77     m_partition = other.m_partition.isolatedCopy();
78     m_type = other.m_type.isolatedCopy();
79     m_identifier = other.m_identifier.isolatedCopy();
80     m_range = other.m_range.isolatedCopy();
81     m_hash = other.m_hash;
82     m_partitionHash = other.m_partitionHash;
83     return *this;
84 }
85
86 static void hashString(SHA1& sha1, const String& string)
87 {
88     if (string.isNull())
89         return;
90
91     if (string.is8Bit() && string.containsOnlyASCII()) {
92         const uint8_t nullByte = 0;
93         sha1.addBytes(string.characters8(), string.length());
94         sha1.addBytes(&nullByte, 1);
95         return;
96     }
97     auto cString = string.utf8();
98     // Include terminating null byte.
99     sha1.addBytes(reinterpret_cast<const uint8_t*>(cString.data()), cString.length() + 1);
100 }
101
102 Key::HashType Key::computeHash(const Salt& salt) const
103 {
104     // We don't really need a cryptographic hash. The key is always verified against the entry header.
105     // SHA1 just happens to be suitably sized, fast and available.
106     SHA1 sha1;
107     sha1.addBytes(salt.data(), salt.size());
108
109     hashString(sha1, m_partition);
110     hashString(sha1, m_type);
111     hashString(sha1, m_identifier);
112     hashString(sha1, m_range);
113
114     SHA1::Digest hash;
115     sha1.computeHash(hash);
116     return hash;
117 }
118
119 Key::HashType Key::computePartitionHash(const Salt& salt) const
120 {
121     SHA1 sha1;
122     sha1.addBytes(salt.data(), salt.size());
123
124     hashString(sha1, m_partition);
125
126     SHA1::Digest hash;
127     sha1.computeHash(hash);
128     return hash;
129 }
130
131 String Key::hashAsString(const HashType& hash)
132 {
133     StringBuilder builder;
134     builder.reserveCapacity(hashStringLength());
135     for (auto byte : hash) {
136         builder.append(upperNibbleToASCIIHexDigit(byte));
137         builder.append(lowerNibbleToASCIIHexDigit(byte));
138     }
139     return builder.toString();
140 }
141
142 template <typename CharType> bool hexDigitsToHash(CharType* characters, Key::HashType& hash)
143 {
144     for (unsigned i = 0; i < sizeof(hash); ++i) {
145         auto high = characters[2 * i];
146         auto low = characters[2 * i + 1];
147         if (!isASCIIHexDigit(high) || !isASCIIHexDigit(low))
148             return false;
149         hash[i] = toASCIIHexValue(high, low);
150     }
151     return true;
152 }
153
154 bool Key::stringToHash(const String& string, HashType& hash)
155 {
156     if (string.length() != hashStringLength())
157         return false;
158     if (string.is8Bit())
159         return hexDigitsToHash(string.characters8(), hash);
160     return hexDigitsToHash(string.characters16(), hash);
161 }
162
163 bool Key::operator==(const Key& other) const
164 {
165     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;
166 }
167
168 void Key::encode(WTF::Persistence::Encoder& encoder) const
169 {
170     encoder << m_partition;
171     encoder << m_type;
172     encoder << m_identifier;
173     encoder << m_range;
174     encoder << m_hash;
175     encoder << m_partitionHash;
176 }
177
178 bool Key::decode(WTF::Persistence::Decoder& decoder, Key& key)
179 {
180     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);
181 }
182
183 }
184 }
185
186 #endif