1a310b93bb8e80a4e27731031cf487c0fbdabe95
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / IDBSerialization.cpp
1 /*
2  * Copyright (C) 2014, 2016 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 #include "config.h"
26 #include "IDBSerialization.h"
27
28 #if ENABLE(INDEXED_DATABASE)
29
30 #include "IDBKeyData.h"
31 #include "IDBKeyPath.h"
32 #include "KeyedCoding.h"
33
34 namespace WebCore {
35
36 enum class KeyPathType { Null, String, Array };
37
38 RefPtr<SharedBuffer> serializeIDBKeyPath(const Optional<IDBKeyPath>& keyPath)
39 {
40     auto encoder = KeyedEncoder::encoder();
41
42     if (keyPath) {
43         auto visitor = WTF::makeVisitor([&](const String& string) {
44             encoder->encodeEnum("type", KeyPathType::String);
45             encoder->encodeString("string", string);
46         }, [&](const Vector<String>& vector) {
47             encoder->encodeEnum("type", KeyPathType::Array);
48             encoder->encodeObjects("array", vector.begin(), vector.end(), [](WebCore::KeyedEncoder& encoder, const String& string) {
49                 encoder.encodeString("string", string);
50             });
51         });
52         WTF::visit(visitor, keyPath.value());
53     } else
54         encoder->encodeEnum("type", KeyPathType::Null);
55
56     return encoder->finishEncoding();
57 }
58
59 bool deserializeIDBKeyPath(const uint8_t* data, size_t size, Optional<IDBKeyPath>& result)
60 {
61     if (!data || !size)
62         return false;
63
64     auto decoder = KeyedDecoder::decoder(data, size);
65
66     KeyPathType type;
67     bool succeeded = decoder->decodeEnum("type", type, [](KeyPathType value) {
68         return value == KeyPathType::Null || value == KeyPathType::String || value == KeyPathType::Array;
69     });
70     if (!succeeded)
71         return false;
72
73     switch (type) {
74     case KeyPathType::Null:
75         break;
76     case KeyPathType::String: {
77         String string;
78         if (!decoder->decodeString("string", string))
79             return false;
80         result = IDBKeyPath(WTFMove(string));
81         break;
82     }
83     case KeyPathType::Array: {
84         Vector<String> vector;
85         succeeded = decoder->decodeObjects("array", vector, [](KeyedDecoder& decoder, String& result) {
86             return decoder.decodeString("string", result);
87         });
88         if (!succeeded)
89             return false;
90         result = IDBKeyPath(WTFMove(vector));
91         break;
92     }
93     }
94     return true;
95 }
96
97 // This is the magic character that begins serialized PropertyLists, and tells us whether
98 // the key we're looking at is an old-style key.
99 static const uint8_t LegacySerializedKeyVersion = 'b';
100
101 // FIXME: Linux ports uses KeyedEncoderGlib for their IDBKeys.
102 // When a Glib maintainer comes along to enable the new serialization they'll need to
103 // denote a Glib magic character here.
104
105 /*
106 The IDBKeyData serialization format is as follows:
107 [1 byte version header][Key Buffer]
108
109 The Key Buffer serialization format is as follows:
110 [1 byte key type][Type specific data]
111
112 Type specific serialization formats are as follows for each of the types:
113 Min:
114 [0 bytes]
115
116 Number:
117 [8 bytes representing a double encoded in little endian]
118
119 Date:
120 [8 bytes representing a double encoded in little endian]
121
122 String:
123 [4 bytes representing string "length" in little endian]["length" number of 2-byte pairs representing ECMAScript 16-bit code units]
124
125 Binary:
126 [8 bytes representing the "size" of the binary blob]["size" bytes]
127
128 Array:
129 [8 bytes representing the "length" of the key array]["length" individual Key Buffer entries]
130
131 Max:
132 [0 bytes]
133 */
134
135 // FIXME: If the GLib magic character ends up being 0x00, we should consider changing
136 // this 0x00 so we can support Glib keyed encoding, also.
137 static const uint8_t SIDBKeyVersion = 0x00;
138 enum class SIDBKeyType : uint8_t {
139     Min = 0x00,
140     Number = 0x20,
141     Date = 0x40,
142     String = 0x60,
143     Binary = 0x80,
144     Array = 0xA0,
145     Max = 0xFF,
146 };
147
148 static SIDBKeyType serializedTypeForKeyType(IndexedDB::KeyType type)
149 {
150     switch (type) {
151     case IndexedDB::KeyType::Min:
152         return SIDBKeyType::Min;
153     case IndexedDB::KeyType::Number:
154         return SIDBKeyType::Number;
155     case IndexedDB::KeyType::Date:
156         return SIDBKeyType::Date;
157     case IndexedDB::KeyType::String:
158         return SIDBKeyType::String;
159     case IndexedDB::KeyType::Binary:
160         return SIDBKeyType::Binary;
161     case IndexedDB::KeyType::Array:
162         return SIDBKeyType::Array;
163     case IndexedDB::KeyType::Max:
164         return SIDBKeyType::Max;
165     case IndexedDB::KeyType::Invalid:
166         RELEASE_ASSERT_NOT_REACHED();
167     };
168
169     RELEASE_ASSERT_NOT_REACHED();
170 }
171
172 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
173 template <typename T> static void writeLittleEndian(Vector<char>& buffer, T value)
174 {
175     for (unsigned i = 0; i < sizeof(T); i++) {
176         buffer.append(value & 0xFF);
177         value >>= 8;
178     }
179 }
180
181 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
182 {
183     if (ptr > end - sizeof(value))
184         return false;
185
186     value = 0;
187     for (size_t i = 0; i < sizeof(T); i++)
188         value += ((T)*ptr++) << (i * 8);
189     return true;
190 }
191 #else
192 template <typename T> static void writeLittleEndian(Vector<char>& buffer, T value)
193 {
194     buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
195 }
196
197 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
198 {
199     if (ptr > end - sizeof(value))
200         return false;
201
202     value = *reinterpret_cast<const T*>(ptr);
203     ptr += sizeof(T);
204
205     return true;
206 }
207 #endif
208
209 static void writeDouble(Vector<char>& data, double d)
210 {
211     writeLittleEndian(data, *reinterpret_cast<uint64_t*>(&d));
212 }
213
214 static bool readDouble(const uint8_t*& data, const uint8_t* end, double& d)
215 {
216     return readLittleEndian(data, end, *reinterpret_cast<uint64_t*>(&d));
217 }
218
219 static void encodeKey(Vector<char>& data, const IDBKeyData& key)
220 {
221     SIDBKeyType type = serializedTypeForKeyType(key.type());
222     data.append(static_cast<char>(type));
223
224     switch (type) {
225     case SIDBKeyType::Number:
226         writeDouble(data, key.number());
227         break;
228     case SIDBKeyType::Date:
229         writeDouble(data, key.date());
230         break;
231     case SIDBKeyType::String: {
232         auto string = key.string();
233         uint32_t length = string.length();
234         writeLittleEndian(data, length);
235
236         for (size_t i = 0; i < length; ++i)
237             writeLittleEndian(data, string[i]);
238
239         break;
240     }
241     case SIDBKeyType::Binary: {
242         auto& buffer = key.binary();
243         uint64_t size = buffer.size();
244         writeLittleEndian(data, size);
245
246         auto* bufferData = buffer.data();
247         ASSERT(bufferData || !size);
248         if (bufferData)
249             data.append(bufferData->data(), bufferData->size());
250
251         break;
252     }
253     case SIDBKeyType::Array: {
254         auto& array = key.array();
255         uint64_t size = array.size();
256         writeLittleEndian(data, size);
257         for (auto& key : array)
258             encodeKey(data, key);
259
260         break;
261     }
262     case SIDBKeyType::Min:
263     case SIDBKeyType::Max:
264         break;
265     }
266 }
267
268 RefPtr<SharedBuffer> serializeIDBKeyData(const IDBKeyData& key)
269 {
270 #if USE(CF)
271     Vector<char> data;
272     data.append(SIDBKeyVersion);
273
274     encodeKey(data, key);
275     return SharedBuffer::adoptVector(data);
276 #else
277     auto encoder = KeyedEncoder::encoder();
278     key.encode(*encoder);
279     return encoder->finishEncoding();
280 #endif
281
282 }
283
284 static bool decodeKey(const uint8_t*& data, const uint8_t* end, IDBKeyData& result)
285 {
286     if (!data || data >= end)
287         return false;
288
289     SIDBKeyType type = static_cast<SIDBKeyType>(data++[0]);
290     switch (type) {
291     case SIDBKeyType::Min:
292         result = IDBKeyData::minimum();
293         return true;
294     case SIDBKeyType::Max:
295         result = IDBKeyData::maximum();
296         return true;
297     case SIDBKeyType::Number: {
298         double d;
299         if (!readDouble(data, end, d))
300             return false;
301
302         result.setNumberValue(d);
303         return true;
304     }
305     case SIDBKeyType::Date: {
306         double d;
307         if (!readDouble(data, end, d))
308             return false;
309
310         result.setDateValue(d);
311         return true;
312     }
313     case SIDBKeyType::String: {
314         uint32_t length;
315         if (!readLittleEndian(data, end, length))
316             return false;
317
318         if (static_cast<uint64_t>(end - data) < length * 2)
319             return false;
320
321         Vector<UChar> buffer;
322         buffer.reserveInitialCapacity(length);
323         for (size_t i = 0; i < length; i++) {
324             uint16_t ch;
325             if (!readLittleEndian(data, end, ch))
326                 return false;
327             buffer.uncheckedAppend(ch);
328         }
329
330         result.setStringValue(String::adopt(WTFMove(buffer)));
331
332         return true;
333     }
334     case SIDBKeyType::Binary: {
335         uint64_t size64;
336         if (!readLittleEndian(data, end, size64))
337             return false;
338
339         if (static_cast<uint64_t>(end - data) < size64)
340             return false;
341
342         if (size64 > std::numeric_limits<size_t>::max())
343             return false;
344
345         size_t size = static_cast<size_t>(size64);
346         Vector<uint8_t> dataVector;
347
348         dataVector.append(data, size);
349         data += size;
350
351         result.setBinaryValue(ThreadSafeDataBuffer::adoptVector(dataVector));
352         return true;
353     }
354     case SIDBKeyType::Array: {
355         uint64_t size64;
356         if (!readLittleEndian(data, end, size64))
357             return false;
358
359         if (size64 > std::numeric_limits<size_t>::max())
360             return false;
361
362         size_t size = static_cast<size_t>(size64);
363         Vector<IDBKeyData> array;
364         array.reserveInitialCapacity(size);
365
366         for (size_t i = 0; i < size; ++i) {
367             IDBKeyData keyData;
368             if (!decodeKey(data, end, keyData))
369                 return false;
370
371             ASSERT(keyData.isValid());
372             array.uncheckedAppend(WTFMove(keyData));
373         }
374
375         result.setArrayValue(array);
376
377         return true;
378     }
379     default:
380         LOG_ERROR("decodeKey encountered unexpected type: %i", (int)type);
381         return false;
382     }
383 }
384
385 bool deserializeIDBKeyData(const uint8_t* data, size_t size, IDBKeyData& result)
386 {
387     if (!data || !size)
388         return false;
389
390 #if USE(CF)
391     if (data[0] == LegacySerializedKeyVersion) {
392         auto decoder = KeyedDecoder::decoder(data, size);
393         return IDBKeyData::decode(*decoder, result);
394     }
395
396     // Verify this is a SerializedIDBKey version we understand.
397     const uint8_t* current = data;
398     const uint8_t* end = data + size;
399     if (current++[0] != SIDBKeyVersion)
400         return false;
401
402     if (decodeKey(current, end, result)) {
403         // Even if we successfully decoded a key, the deserialize is only successful
404         // if we actually consumed all input data.
405         return current == end;
406     }
407
408     return false;
409 #else
410     auto decoder = KeyedDecoder::decoder(data, size);
411     return IDBKeyData::decode(*decoder, result);
412 #endif
413 }
414
415 } // namespace WebCore
416
417 #endif // ENABLE(INDEXED_DATABASE)