OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2010 Google 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 are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "config.h" | |
32 #include "bindings/v8/SerializedScriptValue.h" | |
33 | |
34 #include "bindings/core/v8/V8Blob.h" | |
35 #include "bindings/core/v8/V8File.h" | |
36 #include "bindings/core/v8/V8FileList.h" | |
37 #include "bindings/core/v8/V8ImageData.h" | |
38 #include "bindings/core/v8/V8MessagePort.h" | |
39 #include "bindings/core/v8/custom/V8ArrayBufferCustom.h" | |
40 #include "bindings/core/v8/custom/V8ArrayBufferViewCustom.h" | |
41 #include "bindings/core/v8/custom/V8DataViewCustom.h" | |
42 #include "bindings/core/v8/custom/V8Float32ArrayCustom.h" | |
43 #include "bindings/core/v8/custom/V8Float64ArrayCustom.h" | |
44 #include "bindings/core/v8/custom/V8Int16ArrayCustom.h" | |
45 #include "bindings/core/v8/custom/V8Int32ArrayCustom.h" | |
46 #include "bindings/core/v8/custom/V8Int8ArrayCustom.h" | |
47 #include "bindings/core/v8/custom/V8Uint16ArrayCustom.h" | |
48 #include "bindings/core/v8/custom/V8Uint32ArrayCustom.h" | |
49 #include "bindings/core/v8/custom/V8Uint8ArrayCustom.h" | |
50 #include "bindings/core/v8/custom/V8Uint8ClampedArrayCustom.h" | |
51 #include "bindings/modules/v8/V8CryptoKey.h" | |
52 #include "bindings/modules/v8/V8DOMFileSystem.h" | |
53 #include "bindings/v8/ExceptionState.h" | |
54 #include "bindings/v8/V8Binding.h" | |
55 #include "bindings/v8/WorkerScriptController.h" | |
56 #include "core/dom/ExceptionCode.h" | |
57 #include "core/dom/MessagePort.h" | |
58 #include "core/fileapi/Blob.h" | |
59 #include "core/fileapi/File.h" | |
60 #include "core/fileapi/FileList.h" | |
61 #include "core/html/ImageData.h" | |
62 #include "core/html/canvas/DataView.h" | |
63 #include "platform/SharedBuffer.h" | |
64 #include "platform/heap/Handle.h" | |
65 #include "public/platform/Platform.h" | |
66 #include "public/platform/WebBlobInfo.h" | |
67 #include "public/platform/WebCrypto.h" | |
68 #include "public/platform/WebCryptoKey.h" | |
69 #include "public/platform/WebCryptoKeyAlgorithm.h" | |
70 #include "wtf/ArrayBuffer.h" | |
71 #include "wtf/ArrayBufferContents.h" | |
72 #include "wtf/ArrayBufferView.h" | |
73 #include "wtf/Assertions.h" | |
74 #include "wtf/ByteOrder.h" | |
75 #include "wtf/Float32Array.h" | |
76 #include "wtf/Float64Array.h" | |
77 #include "wtf/Int16Array.h" | |
78 #include "wtf/Int32Array.h" | |
79 #include "wtf/Int8Array.h" | |
80 #include "wtf/RefCounted.h" | |
81 #include "wtf/Uint16Array.h" | |
82 #include "wtf/Uint32Array.h" | |
83 #include "wtf/Uint8Array.h" | |
84 #include "wtf/Uint8ClampedArray.h" | |
85 #include "wtf/Vector.h" | |
86 #include "wtf/text/StringBuffer.h" | |
87 #include "wtf/text/StringUTF8Adaptor.h" | |
88 | |
89 // FIXME: consider crashing in debug mode on deserialization errors | |
90 // NOTE: be sure to change wireFormatVersion as necessary! | |
91 | |
92 namespace WebCore { | |
93 | |
94 namespace { | |
95 | |
96 // This code implements the HTML5 Structured Clone algorithm: | |
97 // http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#safe-pa
ssing-of-structured-data | |
98 | |
99 // V8ObjectMap is a map from V8 objects to arbitrary values of type T. | |
100 // V8 objects (or handles to V8 objects) cannot be used as keys in ordinary wtf:
:HashMaps; | |
101 // this class should be used instead. GCObject must be a subtype of v8::Object. | |
102 // Suggested usage: | |
103 // V8ObjectMap<v8::Object, int> map; | |
104 // v8::Handle<v8::Object> obj = ...; | |
105 // map.set(obj, 42); | |
106 template<typename GCObject, typename T> | |
107 class V8ObjectMap { | |
108 public: | |
109 bool contains(const v8::Handle<GCObject>& handle) | |
110 { | |
111 return m_map.contains(*handle); | |
112 } | |
113 | |
114 bool tryGet(const v8::Handle<GCObject>& handle, T* valueOut) | |
115 { | |
116 typename HandleToT::iterator result = m_map.find(*handle); | |
117 if (result != m_map.end()) { | |
118 *valueOut = result->value; | |
119 return true; | |
120 } | |
121 return false; | |
122 } | |
123 | |
124 void set(const v8::Handle<GCObject>& handle, const T& value) | |
125 { | |
126 m_map.set(*handle, value); | |
127 } | |
128 | |
129 private: | |
130 // This implementation uses GetIdentityHash(), which sets a hidden property
on the object containing | |
131 // a random integer (or returns the one that had been previously set). This
ensures that the table | |
132 // never needs to be rebuilt across garbage collections at the expense of do
ing additional allocation | |
133 // and making more round trips into V8. Note that since GetIdentityHash() is
defined only on | |
134 // v8::Objects, this V8ObjectMap cannot be used to map v8::Strings to T (bec
ause the public V8 API | |
135 // considers a v8::String to be a v8::Primitive). | |
136 | |
137 // If V8 exposes a way to get at the address of the object held by a handle,
then we can produce | |
138 // an alternate implementation that does not need to do any V8-side allocati
on; however, it will | |
139 // need to rehash after every garbage collection because a key object may ha
ve been moved. | |
140 template<typename G> | |
141 struct V8HandlePtrHash { | |
142 static v8::Handle<G> unsafeHandleFromRawValue(const G* value) | |
143 { | |
144 const v8::Handle<G>* handle = reinterpret_cast<const v8::Handle<G>*>
(&value); | |
145 return *handle; | |
146 } | |
147 | |
148 static unsigned hash(const G* key) | |
149 { | |
150 return static_cast<unsigned>(unsafeHandleFromRawValue(key)->GetIdent
ityHash()); | |
151 } | |
152 static bool equal(const G* a, const G* b) | |
153 { | |
154 return unsafeHandleFromRawValue(a) == unsafeHandleFromRawValue(b); | |
155 } | |
156 // For HashArg. | |
157 static const bool safeToCompareToEmptyOrDeleted = false; | |
158 }; | |
159 | |
160 typedef WTF::HashMap<GCObject*, T, V8HandlePtrHash<GCObject> > HandleToT; | |
161 HandleToT m_map; | |
162 }; | |
163 | |
164 typedef UChar BufferValueType; | |
165 | |
166 // Serialization format is a sequence of tags followed by zero or more data argu
ments. | |
167 // Tags always take exactly one byte. A serialized stream first begins with | |
168 // a complete VersionTag. If the stream does not begin with a VersionTag, we ass
ume that | |
169 // the stream is in format 0. | |
170 | |
171 // This format is private to the implementation of SerializedScriptValue. Do not
rely on it | |
172 // externally. It is safe to persist a SerializedScriptValue as a binary blob, b
ut this | |
173 // code should always be used to interpret it. | |
174 | |
175 // WebCoreStrings are read as (length:uint32_t, string:UTF8[length]). | |
176 // RawStrings are read as (length:uint32_t, string:UTF8[length]). | |
177 // RawUCharStrings are read as (length:uint32_t, string:UChar[length/sizeof(UCha
r)]). | |
178 // RawFiles are read as (path:WebCoreString, url:WebCoreStrng, type:WebCoreStrin
g). | |
179 // There is a reference table that maps object references (uint32_t) to v8::Valu
es. | |
180 // Tokens marked with (ref) are inserted into the reference table and given the
next object reference ID after decoding. | |
181 // All tags except InvalidTag, PaddingTag, ReferenceCountTag, VersionTag, Genera
teFreshObjectTag | |
182 // and GenerateFreshArrayTag push their results to the deserialization stack
. | |
183 // There is also an 'open' stack that is used to resolve circular references. Ob
jects or arrays may | |
184 // contain self-references. Before we begin to deserialize the contents of t
hese values, they | |
185 // are first given object reference IDs (by GenerateFreshObjectTag/GenerateF
reshArrayTag); | |
186 // these reference IDs are then used with ObjectReferenceTag to tie the recu
rsive knot. | |
187 enum SerializationTag { | |
188 InvalidTag = '!', // Causes deserialization to fail. | |
189 PaddingTag = '\0', // Is ignored (but consumed). | |
190 UndefinedTag = '_', // -> <undefined> | |
191 NullTag = '0', // -> <null> | |
192 TrueTag = 'T', // -> <true> | |
193 FalseTag = 'F', // -> <false> | |
194 StringTag = 'S', // string:RawString -> string | |
195 StringUCharTag = 'c', // string:RawUCharString -> string | |
196 Int32Tag = 'I', // value:ZigZag-encoded int32 -> Integer | |
197 Uint32Tag = 'U', // value:uint32_t -> Integer | |
198 DateTag = 'D', // value:double -> Date (ref) | |
199 MessagePortTag = 'M', // index:int -> MessagePort. Fills the result with tra
nsferred MessagePort. | |
200 NumberTag = 'N', // value:double -> Number | |
201 BlobTag = 'b', // uuid:WebCoreString, type:WebCoreString, size:uint64_t -> B
lob (ref) | |
202 BlobIndexTag = 'i', // index:int32_t -> Blob (ref) | |
203 FileTag = 'f', // file:RawFile -> File (ref) | |
204 FileIndexTag = 'e', // index:int32_t -> File (ref) | |
205 DOMFileSystemTag = 'd', // type:int32_t, name:WebCoreString, uuid:WebCoreStr
ing -> FileSystem (ref) | |
206 FileListTag = 'l', // length:uint32_t, files:RawFile[length] -> FileList (re
f) | |
207 FileListIndexTag = 'L', // length:uint32_t, files:int32_t[length] -> FileLis
t (ref) | |
208 ImageDataTag = '#', // width:uint32_t, height:uint32_t, pixelDataLength:uint
32_t, data:byte[pixelDataLength] -> ImageData (ref) | |
209 ObjectTag = '{', // numProperties:uint32_t -> pops the last object from the
open stack; | |
210 // fills it with the last numProp
erties name,value pairs pushed onto the deserialization stack | |
211 SparseArrayTag = '@', // numProperties:uint32_t, length:uint32_t -> pops the
last object from the open stack; | |
212 // fills it
with the last numProperties name,value pairs pushed onto the deserialization st
ack | |
213 DenseArrayTag = '$', // numProperties:uint32_t, length:uint32_t -> pops the
last object from the open stack; | |
214 // fills it
with the last length elements and numProperties name,value pairs pushed onto des
erialization stack | |
215 RegExpTag = 'R', // pattern:RawString, flags:uint32_t -> RegExp (ref) | |
216 ArrayBufferTag = 'B', // byteLength:uint32_t, data:byte[byteLength] -> Array
Buffer (ref) | |
217 ArrayBufferTransferTag = 't', // index:uint32_t -> ArrayBuffer. For ArrayBuf
fer transfer | |
218 ArrayBufferViewTag = 'V', // subtag:byte, byteOffset:uint32_t, byteLength:ui
nt32_t -> ArrayBufferView (ref). Consumes an ArrayBuffer from the top of the des
erialization stack. | |
219 CryptoKeyTag = 'K', // subtag:byte, props, usages:uint32_t, keyDataLength:ui
nt32_t, keyData:byte[keyDataLength] | |
220 // If subtag=AesKeyTag: | |
221 // props = keyLengthBytes:uint32_t, algorithmId:ui
nt32_t | |
222 // If subtag=HmacKeyTag: | |
223 // props = keyLengthBytes:uint32_t, hashId:uint32_
t | |
224 // If subtag=RsaHashedKeyTag: | |
225 // props = algorithmId:uint32_t, type:uint32_t, mo
dulusLengthBits:uint32_t, publicExponentLength:uint32_t, publicExponent:byte[pub
licExponentLength], hashId:uint32_t | |
226 ObjectReferenceTag = '^', // ref:uint32_t -> reference table[ref] | |
227 GenerateFreshObjectTag = 'o', // -> empty object allocated an object ID and
pushed onto the open stack (ref) | |
228 GenerateFreshSparseArrayTag = 'a', // length:uint32_t -> empty array[length]
allocated an object ID and pushed onto the open stack (ref) | |
229 GenerateFreshDenseArrayTag = 'A', // length:uint32_t -> empty array[length]
allocated an object ID and pushed onto the open stack (ref) | |
230 ReferenceCountTag = '?', // refTableSize:uint32_t -> If the reference table
is not refTableSize big, fails. | |
231 StringObjectTag = 's', // string:RawString -> new String(string) (ref) | |
232 NumberObjectTag = 'n', // value:double -> new Number(value) (ref) | |
233 TrueObjectTag = 'y', // new Boolean(true) (ref) | |
234 FalseObjectTag = 'x', // new Boolean(false) (ref) | |
235 VersionTag = 0xFF // version:uint32_t -> Uses this as the file version. | |
236 }; | |
237 | |
238 enum ArrayBufferViewSubTag { | |
239 ByteArrayTag = 'b', | |
240 UnsignedByteArrayTag = 'B', | |
241 UnsignedByteClampedArrayTag = 'C', | |
242 ShortArrayTag = 'w', | |
243 UnsignedShortArrayTag = 'W', | |
244 IntArrayTag = 'd', | |
245 UnsignedIntArrayTag = 'D', | |
246 FloatArrayTag = 'f', | |
247 DoubleArrayTag = 'F', | |
248 DataViewTag = '?' | |
249 }; | |
250 | |
251 enum CryptoKeySubTag { | |
252 AesKeyTag = 1, | |
253 HmacKeyTag = 2, | |
254 // ID 3 was used by RsaKeyTag, while still behind experimental flag. | |
255 RsaHashedKeyTag = 4, | |
256 // Maximum allowed value is 255 | |
257 }; | |
258 | |
259 enum AssymetricCryptoKeyType { | |
260 PublicKeyType = 1, | |
261 PrivateKeyType = 2, | |
262 // Maximum allowed value is 2^32-1 | |
263 }; | |
264 | |
265 enum CryptoKeyAlgorithmTag { | |
266 AesCbcTag = 1, | |
267 HmacTag = 2, | |
268 RsaSsaPkcs1v1_5Tag = 3, | |
269 // ID 4 was used by RsaEs, while still behind experimental flag. | |
270 Sha1Tag = 5, | |
271 Sha256Tag = 6, | |
272 Sha384Tag = 7, | |
273 Sha512Tag = 8, | |
274 AesGcmTag = 9, | |
275 RsaOaepTag = 10, | |
276 AesCtrTag = 11, | |
277 AesKwTag = 12, | |
278 // Maximum allowed value is 2^32-1 | |
279 }; | |
280 | |
281 enum CryptoKeyUsage { | |
282 // Extractability is not a "usage" in the WebCryptoKeyUsages sense, however | |
283 // it fits conveniently into this bitfield. | |
284 ExtractableUsage = 1 << 0, | |
285 | |
286 EncryptUsage = 1 << 1, | |
287 DecryptUsage = 1 << 2, | |
288 SignUsage = 1 << 3, | |
289 VerifyUsage = 1 << 4, | |
290 DeriveKeyUsage = 1 << 5, | |
291 WrapKeyUsage = 1 << 6, | |
292 UnwrapKeyUsage = 1 << 7, | |
293 DeriveBitsUsage = 1 << 8, | |
294 // Maximum allowed value is 1 << 31 | |
295 }; | |
296 | |
297 static bool shouldCheckForCycles(int depth) | |
298 { | |
299 ASSERT(depth >= 0); | |
300 // Since we are not required to spot the cycle as soon as it | |
301 // happens we can check for cycles only when the current depth | |
302 // is a power of two. | |
303 return !(depth & (depth - 1)); | |
304 } | |
305 | |
306 static const int maxDepth = 20000; | |
307 | |
308 // VarInt encoding constants. | |
309 static const int varIntShift = 7; | |
310 static const int varIntMask = (1 << varIntShift) - 1; | |
311 | |
312 // ZigZag encoding helps VarInt encoding stay small for negative | |
313 // numbers with small absolute values. | |
314 class ZigZag { | |
315 public: | |
316 static uint32_t encode(uint32_t value) | |
317 { | |
318 if (value & (1U << 31)) | |
319 value = ((~value) << 1) + 1; | |
320 else | |
321 value <<= 1; | |
322 return value; | |
323 } | |
324 | |
325 static uint32_t decode(uint32_t value) | |
326 { | |
327 if (value & 1) | |
328 value = ~(value >> 1); | |
329 else | |
330 value >>= 1; | |
331 return value; | |
332 } | |
333 | |
334 private: | |
335 ZigZag(); | |
336 }; | |
337 | |
338 // Writer is responsible for serializing primitive types and storing | |
339 // information used to reconstruct composite types. | |
340 class Writer { | |
341 WTF_MAKE_NONCOPYABLE(Writer); | |
342 public: | |
343 Writer() | |
344 : m_position(0) | |
345 { | |
346 } | |
347 | |
348 // Write functions for primitive types. | |
349 | |
350 void writeUndefined() { append(UndefinedTag); } | |
351 | |
352 void writeNull() { append(NullTag); } | |
353 | |
354 void writeTrue() { append(TrueTag); } | |
355 | |
356 void writeFalse() { append(FalseTag); } | |
357 | |
358 void writeBooleanObject(bool value) | |
359 { | |
360 append(value ? TrueObjectTag : FalseObjectTag); | |
361 } | |
362 | |
363 void writeOneByteString(v8::Handle<v8::String>& string) | |
364 { | |
365 int stringLength = string->Length(); | |
366 int utf8Length = string->Utf8Length(); | |
367 ASSERT(stringLength >= 0 && utf8Length >= 0); | |
368 | |
369 append(StringTag); | |
370 doWriteUint32(static_cast<uint32_t>(utf8Length)); | |
371 ensureSpace(utf8Length); | |
372 | |
373 // ASCII fast path. | |
374 if (stringLength == utf8Length) | |
375 string->WriteOneByte(byteAt(m_position), 0, utf8Length, v8StringWrit
eOptions()); | |
376 else { | |
377 char* buffer = reinterpret_cast<char*>(byteAt(m_position)); | |
378 string->WriteUtf8(buffer, utf8Length, 0, v8StringWriteOptions()); | |
379 } | |
380 m_position += utf8Length; | |
381 } | |
382 | |
383 void writeUCharString(v8::Handle<v8::String>& string) | |
384 { | |
385 int length = string->Length(); | |
386 ASSERT(length >= 0); | |
387 | |
388 int size = length * sizeof(UChar); | |
389 int bytes = bytesNeededToWireEncode(static_cast<uint32_t>(size)); | |
390 if ((m_position + 1 + bytes) & 1) | |
391 append(PaddingTag); | |
392 | |
393 append(StringUCharTag); | |
394 doWriteUint32(static_cast<uint32_t>(size)); | |
395 ensureSpace(size); | |
396 | |
397 ASSERT(!(m_position & 1)); | |
398 uint16_t* buffer = reinterpret_cast<uint16_t*>(byteAt(m_position)); | |
399 string->Write(buffer, 0, length, v8StringWriteOptions()); | |
400 m_position += size; | |
401 } | |
402 | |
403 void writeStringObject(const char* data, int length) | |
404 { | |
405 ASSERT(length >= 0); | |
406 append(StringObjectTag); | |
407 doWriteString(data, length); | |
408 } | |
409 | |
410 void writeWebCoreString(const String& string) | |
411 { | |
412 // Uses UTF8 encoding so we can read it back as either V8 or | |
413 // WebCore string. | |
414 append(StringTag); | |
415 doWriteWebCoreString(string); | |
416 } | |
417 | |
418 void writeVersion() | |
419 { | |
420 append(VersionTag); | |
421 doWriteUint32(SerializedScriptValue::wireFormatVersion); | |
422 } | |
423 | |
424 void writeInt32(int32_t value) | |
425 { | |
426 append(Int32Tag); | |
427 doWriteUint32(ZigZag::encode(static_cast<uint32_t>(value))); | |
428 } | |
429 | |
430 void writeUint32(uint32_t value) | |
431 { | |
432 append(Uint32Tag); | |
433 doWriteUint32(value); | |
434 } | |
435 | |
436 void writeDate(double numberValue) | |
437 { | |
438 append(DateTag); | |
439 doWriteNumber(numberValue); | |
440 } | |
441 | |
442 void writeNumber(double number) | |
443 { | |
444 append(NumberTag); | |
445 doWriteNumber(number); | |
446 } | |
447 | |
448 void writeNumberObject(double number) | |
449 { | |
450 append(NumberObjectTag); | |
451 doWriteNumber(number); | |
452 } | |
453 | |
454 void writeBlob(const String& uuid, const String& type, unsigned long long si
ze) | |
455 { | |
456 append(BlobTag); | |
457 doWriteWebCoreString(uuid); | |
458 doWriteWebCoreString(type); | |
459 doWriteUint64(size); | |
460 } | |
461 | |
462 void writeBlobIndex(int blobIndex) | |
463 { | |
464 ASSERT(blobIndex >= 0); | |
465 append(BlobIndexTag); | |
466 doWriteUint32(blobIndex); | |
467 } | |
468 | |
469 void writeDOMFileSystem(int type, const String& name, const String& url) | |
470 { | |
471 append(DOMFileSystemTag); | |
472 doWriteUint32(type); | |
473 doWriteWebCoreString(name); | |
474 doWriteWebCoreString(url); | |
475 } | |
476 | |
477 void writeFile(const File& file) | |
478 { | |
479 append(FileTag); | |
480 doWriteFile(file); | |
481 } | |
482 | |
483 void writeFileIndex(int blobIndex) | |
484 { | |
485 append(FileIndexTag); | |
486 doWriteUint32(blobIndex); | |
487 } | |
488 | |
489 void writeFileList(const FileList& fileList) | |
490 { | |
491 append(FileListTag); | |
492 uint32_t length = fileList.length(); | |
493 doWriteUint32(length); | |
494 for (unsigned i = 0; i < length; ++i) | |
495 doWriteFile(*fileList.item(i)); | |
496 } | |
497 | |
498 void writeFileListIndex(const Vector<int>& blobIndices) | |
499 { | |
500 append(FileListIndexTag); | |
501 uint32_t length = blobIndices.size(); | |
502 doWriteUint32(length); | |
503 for (unsigned i = 0; i < length; ++i) | |
504 doWriteUint32(blobIndices[i]); | |
505 } | |
506 | |
507 bool writeCryptoKey(const blink::WebCryptoKey& key) | |
508 { | |
509 append(static_cast<uint8_t>(CryptoKeyTag)); | |
510 | |
511 switch (key.algorithm().paramsType()) { | |
512 case blink::WebCryptoKeyAlgorithmParamsTypeAes: | |
513 doWriteAesKey(key); | |
514 break; | |
515 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: | |
516 doWriteHmacKey(key); | |
517 break; | |
518 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: | |
519 doWriteRsaHashedKey(key); | |
520 break; | |
521 case blink::WebCryptoKeyAlgorithmParamsTypeNone: | |
522 ASSERT_NOT_REACHED(); | |
523 return false; | |
524 } | |
525 | |
526 doWriteKeyUsages(key.usages(), key.extractable()); | |
527 | |
528 blink::WebVector<uint8_t> keyData; | |
529 if (!blink::Platform::current()->crypto()->serializeKeyForClone(key, key
Data)) | |
530 return false; | |
531 | |
532 doWriteUint32(keyData.size()); | |
533 append(keyData.data(), keyData.size()); | |
534 return true; | |
535 } | |
536 | |
537 void writeArrayBuffer(const ArrayBuffer& arrayBuffer) | |
538 { | |
539 append(ArrayBufferTag); | |
540 doWriteArrayBuffer(arrayBuffer); | |
541 } | |
542 | |
543 void writeArrayBufferView(const ArrayBufferView& arrayBufferView) | |
544 { | |
545 append(ArrayBufferViewTag); | |
546 #ifndef NDEBUG | |
547 const ArrayBuffer& arrayBuffer = *arrayBufferView.buffer(); | |
548 ASSERT(static_cast<const uint8_t*>(arrayBuffer.data()) + arrayBufferView
.byteOffset() == | |
549 static_cast<const uint8_t*>(arrayBufferView.baseAddress())); | |
550 #endif | |
551 ArrayBufferView::ViewType type = arrayBufferView.type(); | |
552 | |
553 if (type == ArrayBufferView::TypeInt8) | |
554 append(ByteArrayTag); | |
555 else if (type == ArrayBufferView::TypeUint8Clamped) | |
556 append(UnsignedByteClampedArrayTag); | |
557 else if (type == ArrayBufferView::TypeUint8) | |
558 append(UnsignedByteArrayTag); | |
559 else if (type == ArrayBufferView::TypeInt16) | |
560 append(ShortArrayTag); | |
561 else if (type == ArrayBufferView::TypeUint16) | |
562 append(UnsignedShortArrayTag); | |
563 else if (type == ArrayBufferView::TypeInt32) | |
564 append(IntArrayTag); | |
565 else if (type == ArrayBufferView::TypeUint32) | |
566 append(UnsignedIntArrayTag); | |
567 else if (type == ArrayBufferView::TypeFloat32) | |
568 append(FloatArrayTag); | |
569 else if (type == ArrayBufferView::TypeFloat64) | |
570 append(DoubleArrayTag); | |
571 else if (type == ArrayBufferView::TypeDataView) | |
572 append(DataViewTag); | |
573 else | |
574 ASSERT_NOT_REACHED(); | |
575 doWriteUint32(arrayBufferView.byteOffset()); | |
576 doWriteUint32(arrayBufferView.byteLength()); | |
577 } | |
578 | |
579 void writeImageData(uint32_t width, uint32_t height, const uint8_t* pixelDat
a, uint32_t pixelDataLength) | |
580 { | |
581 append(ImageDataTag); | |
582 doWriteUint32(width); | |
583 doWriteUint32(height); | |
584 doWriteUint32(pixelDataLength); | |
585 append(pixelData, pixelDataLength); | |
586 } | |
587 | |
588 void writeRegExp(v8::Local<v8::String> pattern, v8::RegExp::Flags flags) | |
589 { | |
590 append(RegExpTag); | |
591 v8::String::Utf8Value patternUtf8Value(pattern); | |
592 doWriteString(*patternUtf8Value, patternUtf8Value.length()); | |
593 doWriteUint32(static_cast<uint32_t>(flags)); | |
594 } | |
595 | |
596 void writeTransferredMessagePort(uint32_t index) | |
597 { | |
598 append(MessagePortTag); | |
599 doWriteUint32(index); | |
600 } | |
601 | |
602 void writeTransferredArrayBuffer(uint32_t index) | |
603 { | |
604 append(ArrayBufferTransferTag); | |
605 doWriteUint32(index); | |
606 } | |
607 | |
608 void writeObjectReference(uint32_t reference) | |
609 { | |
610 append(ObjectReferenceTag); | |
611 doWriteUint32(reference); | |
612 } | |
613 | |
614 void writeObject(uint32_t numProperties) | |
615 { | |
616 append(ObjectTag); | |
617 doWriteUint32(numProperties); | |
618 } | |
619 | |
620 void writeSparseArray(uint32_t numProperties, uint32_t length) | |
621 { | |
622 append(SparseArrayTag); | |
623 doWriteUint32(numProperties); | |
624 doWriteUint32(length); | |
625 } | |
626 | |
627 void writeDenseArray(uint32_t numProperties, uint32_t length) | |
628 { | |
629 append(DenseArrayTag); | |
630 doWriteUint32(numProperties); | |
631 doWriteUint32(length); | |
632 } | |
633 | |
634 String takeWireString() | |
635 { | |
636 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes); | |
637 fillHole(); | |
638 String data = String(m_buffer.data(), m_buffer.size()); | |
639 data.impl()->truncateAssumingIsolated((m_position + 1) / sizeof(BufferVa
lueType)); | |
640 return data; | |
641 } | |
642 | |
643 void writeReferenceCount(uint32_t numberOfReferences) | |
644 { | |
645 append(ReferenceCountTag); | |
646 doWriteUint32(numberOfReferences); | |
647 } | |
648 | |
649 void writeGenerateFreshObject() | |
650 { | |
651 append(GenerateFreshObjectTag); | |
652 } | |
653 | |
654 void writeGenerateFreshSparseArray(uint32_t length) | |
655 { | |
656 append(GenerateFreshSparseArrayTag); | |
657 doWriteUint32(length); | |
658 } | |
659 | |
660 void writeGenerateFreshDenseArray(uint32_t length) | |
661 { | |
662 append(GenerateFreshDenseArrayTag); | |
663 doWriteUint32(length); | |
664 } | |
665 | |
666 private: | |
667 void doWriteFile(const File& file) | |
668 { | |
669 doWriteWebCoreString(file.hasBackingFile() ? file.path() : ""); | |
670 doWriteWebCoreString(file.name()); | |
671 doWriteWebCoreString(file.webkitRelativePath()); | |
672 doWriteWebCoreString(file.uuid()); | |
673 doWriteWebCoreString(file.type()); | |
674 | |
675 // FIXME don't use 4 bytes to encode a flag. | |
676 if (file.hasValidSnapshotMetadata()) { | |
677 doWriteUint32(static_cast<uint8_t>(1)); | |
678 | |
679 long long size; | |
680 double lastModified; | |
681 file.captureSnapshot(size, lastModified); | |
682 doWriteUint64(static_cast<uint64_t>(size)); | |
683 doWriteNumber(lastModified); | |
684 } else { | |
685 append(static_cast<uint8_t>(0)); | |
686 } | |
687 } | |
688 | |
689 void doWriteArrayBuffer(const ArrayBuffer& arrayBuffer) | |
690 { | |
691 uint32_t byteLength = arrayBuffer.byteLength(); | |
692 doWriteUint32(byteLength); | |
693 append(static_cast<const uint8_t*>(arrayBuffer.data()), byteLength); | |
694 } | |
695 | |
696 void doWriteString(const char* data, int length) | |
697 { | |
698 doWriteUint32(static_cast<uint32_t>(length)); | |
699 append(reinterpret_cast<const uint8_t*>(data), length); | |
700 } | |
701 | |
702 void doWriteWebCoreString(const String& string) | |
703 { | |
704 StringUTF8Adaptor stringUTF8(string); | |
705 doWriteString(stringUTF8.data(), stringUTF8.length()); | |
706 } | |
707 | |
708 void doWriteHmacKey(const blink::WebCryptoKey& key) | |
709 { | |
710 ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParam
sTypeHmac); | |
711 | |
712 append(static_cast<uint8_t>(HmacKeyTag)); | |
713 ASSERT(!(key.algorithm().hmacParams()->lengthBits() % 8)); | |
714 doWriteUint32(key.algorithm().hmacParams()->lengthBits() / 8); | |
715 doWriteAlgorithmId(key.algorithm().hmacParams()->hash().id()); | |
716 } | |
717 | |
718 void doWriteAesKey(const blink::WebCryptoKey& key) | |
719 { | |
720 ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParam
sTypeAes); | |
721 | |
722 append(static_cast<uint8_t>(AesKeyTag)); | |
723 doWriteAlgorithmId(key.algorithm().id()); | |
724 // Converting the key length from bits to bytes is lossless and makes | |
725 // it fit in 1 byte. | |
726 ASSERT(!(key.algorithm().aesParams()->lengthBits() % 8)); | |
727 doWriteUint32(key.algorithm().aesParams()->lengthBits() / 8); | |
728 } | |
729 | |
730 void doWriteRsaHashedKey(const blink::WebCryptoKey& key) | |
731 { | |
732 ASSERT(key.algorithm().rsaHashedParams()); | |
733 append(static_cast<uint8_t>(RsaHashedKeyTag)); | |
734 | |
735 doWriteAlgorithmId(key.algorithm().id()); | |
736 | |
737 switch (key.type()) { | |
738 case blink::WebCryptoKeyTypePublic: | |
739 doWriteUint32(PublicKeyType); | |
740 break; | |
741 case blink::WebCryptoKeyTypePrivate: | |
742 doWriteUint32(PrivateKeyType); | |
743 break; | |
744 case blink::WebCryptoKeyTypeSecret: | |
745 ASSERT_NOT_REACHED(); | |
746 } | |
747 | |
748 const blink::WebCryptoRsaHashedKeyAlgorithmParams* params = key.algorith
m().rsaHashedParams(); | |
749 doWriteUint32(params->modulusLengthBits()); | |
750 doWriteUint32(params->publicExponent().size()); | |
751 append(params->publicExponent().data(), params->publicExponent().size())
; | |
752 doWriteAlgorithmId(key.algorithm().rsaHashedParams()->hash().id()); | |
753 } | |
754 | |
755 void doWriteAlgorithmId(blink::WebCryptoAlgorithmId id) | |
756 { | |
757 switch (id) { | |
758 case blink::WebCryptoAlgorithmIdAesCbc: | |
759 return doWriteUint32(AesCbcTag); | |
760 case blink::WebCryptoAlgorithmIdHmac: | |
761 return doWriteUint32(HmacTag); | |
762 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
763 return doWriteUint32(RsaSsaPkcs1v1_5Tag); | |
764 case blink::WebCryptoAlgorithmIdSha1: | |
765 return doWriteUint32(Sha1Tag); | |
766 case blink::WebCryptoAlgorithmIdSha256: | |
767 return doWriteUint32(Sha256Tag); | |
768 case blink::WebCryptoAlgorithmIdSha384: | |
769 return doWriteUint32(Sha384Tag); | |
770 case blink::WebCryptoAlgorithmIdSha512: | |
771 return doWriteUint32(Sha512Tag); | |
772 case blink::WebCryptoAlgorithmIdAesGcm: | |
773 return doWriteUint32(AesGcmTag); | |
774 case blink::WebCryptoAlgorithmIdRsaOaep: | |
775 return doWriteUint32(RsaOaepTag); | |
776 case blink::WebCryptoAlgorithmIdAesCtr: | |
777 return doWriteUint32(AesCtrTag); | |
778 case blink::WebCryptoAlgorithmIdAesKw: | |
779 return doWriteUint32(AesKwTag); | |
780 } | |
781 ASSERT_NOT_REACHED(); | |
782 } | |
783 | |
784 void doWriteKeyUsages(const blink::WebCryptoKeyUsageMask usages, bool extrac
table) | |
785 { | |
786 // Reminder to update this when adding new key usages. | |
787 COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe); | |
788 | |
789 uint32_t value = 0; | |
790 | |
791 if (extractable) | |
792 value |= ExtractableUsage; | |
793 | |
794 if (usages & blink::WebCryptoKeyUsageEncrypt) | |
795 value |= EncryptUsage; | |
796 if (usages & blink::WebCryptoKeyUsageDecrypt) | |
797 value |= DecryptUsage; | |
798 if (usages & blink::WebCryptoKeyUsageSign) | |
799 value |= SignUsage; | |
800 if (usages & blink::WebCryptoKeyUsageVerify) | |
801 value |= VerifyUsage; | |
802 if (usages & blink::WebCryptoKeyUsageDeriveKey) | |
803 value |= DeriveKeyUsage; | |
804 if (usages & blink::WebCryptoKeyUsageWrapKey) | |
805 value |= WrapKeyUsage; | |
806 if (usages & blink::WebCryptoKeyUsageUnwrapKey) | |
807 value |= UnwrapKeyUsage; | |
808 if (usages & blink::WebCryptoKeyUsageDeriveBits) | |
809 value |= DeriveBitsUsage; | |
810 | |
811 doWriteUint32(value); | |
812 } | |
813 | |
814 int bytesNeededToWireEncode(uint32_t value) | |
815 { | |
816 int bytes = 1; | |
817 while (true) { | |
818 value >>= varIntShift; | |
819 if (!value) | |
820 break; | |
821 ++bytes; | |
822 } | |
823 | |
824 return bytes; | |
825 } | |
826 | |
827 template<class T> | |
828 void doWriteUintHelper(T value) | |
829 { | |
830 while (true) { | |
831 uint8_t b = (value & varIntMask); | |
832 value >>= varIntShift; | |
833 if (!value) { | |
834 append(b); | |
835 break; | |
836 } | |
837 append(b | (1 << varIntShift)); | |
838 } | |
839 } | |
840 | |
841 void doWriteUint32(uint32_t value) | |
842 { | |
843 doWriteUintHelper(value); | |
844 } | |
845 | |
846 void doWriteUint64(uint64_t value) | |
847 { | |
848 doWriteUintHelper(value); | |
849 } | |
850 | |
851 void doWriteNumber(double number) | |
852 { | |
853 append(reinterpret_cast<uint8_t*>(&number), sizeof(number)); | |
854 } | |
855 | |
856 void append(SerializationTag tag) | |
857 { | |
858 append(static_cast<uint8_t>(tag)); | |
859 } | |
860 | |
861 void append(uint8_t b) | |
862 { | |
863 ensureSpace(1); | |
864 *byteAt(m_position++) = b; | |
865 } | |
866 | |
867 void append(const uint8_t* data, int length) | |
868 { | |
869 ensureSpace(length); | |
870 memcpy(byteAt(m_position), data, length); | |
871 m_position += length; | |
872 } | |
873 | |
874 void ensureSpace(unsigned extra) | |
875 { | |
876 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes); | |
877 m_buffer.resize((m_position + extra + 1) / sizeof(BufferValueType)); //
"+ 1" to round up. | |
878 } | |
879 | |
880 void fillHole() | |
881 { | |
882 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes); | |
883 // If the writer is at odd position in the buffer, then one of | |
884 // the bytes in the last UChar is not initialized. | |
885 if (m_position % 2) | |
886 *byteAt(m_position) = static_cast<uint8_t>(PaddingTag); | |
887 } | |
888 | |
889 uint8_t* byteAt(int position) | |
890 { | |
891 return reinterpret_cast<uint8_t*>(m_buffer.data()) + position; | |
892 } | |
893 | |
894 int v8StringWriteOptions() | |
895 { | |
896 return v8::String::NO_NULL_TERMINATION; | |
897 } | |
898 | |
899 Vector<BufferValueType> m_buffer; | |
900 unsigned m_position; | |
901 }; | |
902 | |
903 static v8::Handle<v8::Object> toV8Object(MessagePort* impl, v8::Handle<v8::Objec
t> creationContext, v8::Isolate* isolate) | |
904 { | |
905 if (!impl) | |
906 return v8::Handle<v8::Object>(); | |
907 v8::Handle<v8::Value> wrapper = toV8(impl, creationContext, isolate); | |
908 ASSERT(wrapper->IsObject()); | |
909 return wrapper.As<v8::Object>(); | |
910 } | |
911 | |
912 static v8::Handle<v8::ArrayBuffer> toV8Object(ArrayBuffer* impl, v8::Handle<v8::
Object> creationContext, v8::Isolate* isolate) | |
913 { | |
914 if (!impl) | |
915 return v8::Handle<v8::ArrayBuffer>(); | |
916 v8::Handle<v8::Value> wrapper = toV8(impl, creationContext, isolate); | |
917 ASSERT(wrapper->IsArrayBuffer()); | |
918 return wrapper.As<v8::ArrayBuffer>(); | |
919 } | |
920 | |
921 class Serializer { | |
922 class StateBase; | |
923 public: | |
924 enum Status { | |
925 Success, | |
926 InputError, | |
927 DataCloneError, | |
928 JSException | |
929 }; | |
930 | |
931 Serializer(Writer& writer, MessagePortArray* messagePorts, ArrayBufferArray*
arrayBuffers, WebBlobInfoArray* blobInfo, BlobDataHandleMap& blobDataHandles, v
8::TryCatch& tryCatch, ScriptState* scriptState) | |
932 : m_scriptState(scriptState) | |
933 , m_writer(writer) | |
934 , m_tryCatch(tryCatch) | |
935 , m_depth(0) | |
936 , m_status(Success) | |
937 , m_nextObjectReference(0) | |
938 , m_blobInfo(blobInfo) | |
939 , m_blobDataHandles(blobDataHandles) | |
940 { | |
941 ASSERT(!tryCatch.HasCaught()); | |
942 v8::Handle<v8::Object> creationContext = m_scriptState->context()->Globa
l(); | |
943 if (messagePorts) { | |
944 for (size_t i = 0; i < messagePorts->size(); i++) | |
945 m_transferredMessagePorts.set(toV8Object(messagePorts->at(i).get
(), creationContext, isolate()), i); | |
946 } | |
947 if (arrayBuffers) { | |
948 for (size_t i = 0; i < arrayBuffers->size(); i++) { | |
949 v8::Handle<v8::Object> v8ArrayBuffer = toV8Object(arrayBuffers->
at(i).get(), creationContext, isolate()); | |
950 // Coalesce multiple occurences of the same buffer to the first
index. | |
951 if (!m_transferredArrayBuffers.contains(v8ArrayBuffer)) | |
952 m_transferredArrayBuffers.set(v8ArrayBuffer, i); | |
953 } | |
954 } | |
955 } | |
956 | |
957 v8::Isolate* isolate() { return m_scriptState->isolate(); } | |
958 | |
959 Status serialize(v8::Handle<v8::Value> value) | |
960 { | |
961 v8::HandleScope scope(isolate()); | |
962 m_writer.writeVersion(); | |
963 StateBase* state = doSerialize(value, 0); | |
964 while (state) | |
965 state = state->advance(*this); | |
966 return m_status; | |
967 } | |
968 | |
969 String errorMessage() { return m_errorMessage; } | |
970 | |
971 // Functions used by serialization states. | |
972 StateBase* doSerialize(v8::Handle<v8::Value>, StateBase* next); | |
973 | |
974 StateBase* doSerializeArrayBuffer(v8::Handle<v8::Value> arrayBuffer, StateBa
se* next) | |
975 { | |
976 return doSerialize(arrayBuffer, next); | |
977 } | |
978 | |
979 StateBase* checkException(StateBase* state) | |
980 { | |
981 return m_tryCatch.HasCaught() ? handleError(JSException, "", state) : 0; | |
982 } | |
983 | |
984 StateBase* writeObject(uint32_t numProperties, StateBase* state) | |
985 { | |
986 m_writer.writeObject(numProperties); | |
987 return pop(state); | |
988 } | |
989 | |
990 StateBase* writeSparseArray(uint32_t numProperties, uint32_t length, StateBa
se* state) | |
991 { | |
992 m_writer.writeSparseArray(numProperties, length); | |
993 return pop(state); | |
994 } | |
995 | |
996 StateBase* writeDenseArray(uint32_t numProperties, uint32_t length, StateBas
e* state) | |
997 { | |
998 m_writer.writeDenseArray(numProperties, length); | |
999 return pop(state); | |
1000 } | |
1001 | |
1002 | |
1003 private: | |
1004 class StateBase { | |
1005 WTF_MAKE_NONCOPYABLE(StateBase); | |
1006 public: | |
1007 virtual ~StateBase() { } | |
1008 | |
1009 // Link to the next state to form a stack. | |
1010 StateBase* nextState() { return m_next; } | |
1011 | |
1012 // Composite object we're processing in this state. | |
1013 v8::Handle<v8::Value> composite() { return m_composite; } | |
1014 | |
1015 // Serializes (a part of) the current composite and returns | |
1016 // the next state to process or null when this is the final | |
1017 // state. | |
1018 virtual StateBase* advance(Serializer&) = 0; | |
1019 | |
1020 protected: | |
1021 StateBase(v8::Handle<v8::Value> composite, StateBase* next) | |
1022 : m_composite(composite) | |
1023 , m_next(next) | |
1024 { | |
1025 } | |
1026 | |
1027 private: | |
1028 v8::Handle<v8::Value> m_composite; | |
1029 StateBase* m_next; | |
1030 }; | |
1031 | |
1032 // Dummy state that is used to signal serialization errors. | |
1033 class ErrorState FINAL : public StateBase { | |
1034 public: | |
1035 ErrorState() | |
1036 : StateBase(v8Undefined(), 0) | |
1037 { | |
1038 } | |
1039 | |
1040 virtual StateBase* advance(Serializer&) OVERRIDE | |
1041 { | |
1042 delete this; | |
1043 return 0; | |
1044 } | |
1045 }; | |
1046 | |
1047 template <typename T> | |
1048 class State : public StateBase { | |
1049 public: | |
1050 v8::Handle<T> composite() { return v8::Handle<T>::Cast(StateBase::compos
ite()); } | |
1051 | |
1052 protected: | |
1053 State(v8::Handle<T> composite, StateBase* next) | |
1054 : StateBase(composite, next) | |
1055 { | |
1056 } | |
1057 }; | |
1058 | |
1059 class AbstractObjectState : public State<v8::Object> { | |
1060 public: | |
1061 AbstractObjectState(v8::Handle<v8::Object> object, StateBase* next) | |
1062 : State<v8::Object>(object, next) | |
1063 , m_index(0) | |
1064 , m_numSerializedProperties(0) | |
1065 , m_nameDone(false) | |
1066 { | |
1067 } | |
1068 | |
1069 protected: | |
1070 virtual StateBase* objectDone(unsigned numProperties, Serializer&) = 0; | |
1071 | |
1072 StateBase* serializeProperties(bool ignoreIndexed, Serializer& serialize
r) | |
1073 { | |
1074 while (m_index < m_propertyNames->Length()) { | |
1075 if (!m_nameDone) { | |
1076 v8::Local<v8::Value> propertyName = m_propertyNames->Get(m_i
ndex); | |
1077 if (StateBase* newState = serializer.checkException(this)) | |
1078 return newState; | |
1079 if (propertyName.IsEmpty()) | |
1080 return serializer.handleError(InputError, "Empty propert
y names cannot be cloned.", this); | |
1081 bool hasStringProperty = propertyName->IsString() && composi
te()->HasRealNamedProperty(propertyName.As<v8::String>()); | |
1082 if (StateBase* newState = serializer.checkException(this)) | |
1083 return newState; | |
1084 bool hasIndexedProperty = !hasStringProperty && propertyName
->IsUint32() && composite()->HasRealIndexedProperty(propertyName->Uint32Value())
; | |
1085 if (StateBase* newState = serializer.checkException(this)) | |
1086 return newState; | |
1087 if (hasStringProperty || (hasIndexedProperty && !ignoreIndex
ed)) | |
1088 m_propertyName = propertyName; | |
1089 else { | |
1090 ++m_index; | |
1091 continue; | |
1092 } | |
1093 } | |
1094 ASSERT(!m_propertyName.IsEmpty()); | |
1095 if (!m_nameDone) { | |
1096 m_nameDone = true; | |
1097 if (StateBase* newState = serializer.doSerialize(m_propertyN
ame, this)) | |
1098 return newState; | |
1099 } | |
1100 v8::Local<v8::Value> value = composite()->Get(m_propertyName); | |
1101 if (StateBase* newState = serializer.checkException(this)) | |
1102 return newState; | |
1103 m_nameDone = false; | |
1104 m_propertyName.Clear(); | |
1105 ++m_index; | |
1106 ++m_numSerializedProperties; | |
1107 // If we return early here, it's either because we have pushed a
new state onto the | |
1108 // serialization state stack or because we have encountered an e
rror (and in both cases | |
1109 // we are unwinding the native stack). | |
1110 if (StateBase* newState = serializer.doSerialize(value, this)) | |
1111 return newState; | |
1112 } | |
1113 return objectDone(m_numSerializedProperties, serializer); | |
1114 } | |
1115 | |
1116 v8::Local<v8::Array> m_propertyNames; | |
1117 | |
1118 private: | |
1119 v8::Local<v8::Value> m_propertyName; | |
1120 unsigned m_index; | |
1121 unsigned m_numSerializedProperties; | |
1122 bool m_nameDone; | |
1123 }; | |
1124 | |
1125 class ObjectState FINAL : public AbstractObjectState { | |
1126 public: | |
1127 ObjectState(v8::Handle<v8::Object> object, StateBase* next) | |
1128 : AbstractObjectState(object, next) | |
1129 { | |
1130 } | |
1131 | |
1132 virtual StateBase* advance(Serializer& serializer) OVERRIDE | |
1133 { | |
1134 if (m_propertyNames.IsEmpty()) { | |
1135 m_propertyNames = composite()->GetPropertyNames(); | |
1136 if (StateBase* newState = serializer.checkException(this)) | |
1137 return newState; | |
1138 if (m_propertyNames.IsEmpty()) | |
1139 return serializer.handleError(InputError, "Empty property na
mes cannot be cloned.", nextState()); | |
1140 } | |
1141 return serializeProperties(false, serializer); | |
1142 } | |
1143 | |
1144 protected: | |
1145 virtual StateBase* objectDone(unsigned numProperties, Serializer& serial
izer) OVERRIDE | |
1146 { | |
1147 return serializer.writeObject(numProperties, this); | |
1148 } | |
1149 }; | |
1150 | |
1151 class DenseArrayState FINAL : public AbstractObjectState { | |
1152 public: | |
1153 DenseArrayState(v8::Handle<v8::Array> array, v8::Handle<v8::Array> prope
rtyNames, StateBase* next, v8::Isolate* isolate) | |
1154 : AbstractObjectState(array, next) | |
1155 , m_arrayIndex(0) | |
1156 , m_arrayLength(array->Length()) | |
1157 { | |
1158 m_propertyNames = v8::Local<v8::Array>::New(isolate, propertyNames); | |
1159 } | |
1160 | |
1161 virtual StateBase* advance(Serializer& serializer) OVERRIDE | |
1162 { | |
1163 while (m_arrayIndex < m_arrayLength) { | |
1164 v8::Handle<v8::Value> value = composite().As<v8::Array>()->Get(m
_arrayIndex); | |
1165 m_arrayIndex++; | |
1166 if (StateBase* newState = serializer.checkException(this)) | |
1167 return newState; | |
1168 if (StateBase* newState = serializer.doSerialize(value, this)) | |
1169 return newState; | |
1170 } | |
1171 return serializeProperties(true, serializer); | |
1172 } | |
1173 | |
1174 protected: | |
1175 virtual StateBase* objectDone(unsigned numProperties, Serializer& serial
izer) OVERRIDE | |
1176 { | |
1177 return serializer.writeDenseArray(numProperties, m_arrayLength, this
); | |
1178 } | |
1179 | |
1180 private: | |
1181 uint32_t m_arrayIndex; | |
1182 uint32_t m_arrayLength; | |
1183 }; | |
1184 | |
1185 class SparseArrayState FINAL : public AbstractObjectState { | |
1186 public: | |
1187 SparseArrayState(v8::Handle<v8::Array> array, v8::Handle<v8::Array> prop
ertyNames, StateBase* next, v8::Isolate* isolate) | |
1188 : AbstractObjectState(array, next) | |
1189 { | |
1190 m_propertyNames = v8::Local<v8::Array>::New(isolate, propertyNames); | |
1191 } | |
1192 | |
1193 virtual StateBase* advance(Serializer& serializer) OVERRIDE | |
1194 { | |
1195 return serializeProperties(false, serializer); | |
1196 } | |
1197 | |
1198 protected: | |
1199 virtual StateBase* objectDone(unsigned numProperties, Serializer& serial
izer) OVERRIDE | |
1200 { | |
1201 return serializer.writeSparseArray(numProperties, composite().As<v8:
:Array>()->Length(), this); | |
1202 } | |
1203 }; | |
1204 | |
1205 StateBase* push(StateBase* state) | |
1206 { | |
1207 ASSERT(state); | |
1208 ++m_depth; | |
1209 return checkComposite(state) ? state : handleError(InputError, "Value be
ing cloned is either cyclic or too deeply nested.", state); | |
1210 } | |
1211 | |
1212 StateBase* pop(StateBase* state) | |
1213 { | |
1214 ASSERT(state); | |
1215 --m_depth; | |
1216 StateBase* next = state->nextState(); | |
1217 delete state; | |
1218 return next; | |
1219 } | |
1220 | |
1221 StateBase* handleError(Status errorStatus, const String& message, StateBase*
state) | |
1222 { | |
1223 ASSERT(errorStatus != Success); | |
1224 m_status = errorStatus; | |
1225 m_errorMessage = message; | |
1226 while (state) { | |
1227 StateBase* tmp = state->nextState(); | |
1228 delete state; | |
1229 state = tmp; | |
1230 } | |
1231 return new ErrorState; | |
1232 } | |
1233 | |
1234 bool checkComposite(StateBase* top) | |
1235 { | |
1236 ASSERT(top); | |
1237 if (m_depth > maxDepth) | |
1238 return false; | |
1239 if (!shouldCheckForCycles(m_depth)) | |
1240 return true; | |
1241 v8::Handle<v8::Value> composite = top->composite(); | |
1242 for (StateBase* state = top->nextState(); state; state = state->nextStat
e()) { | |
1243 if (state->composite() == composite) | |
1244 return false; | |
1245 } | |
1246 return true; | |
1247 } | |
1248 | |
1249 void writeString(v8::Handle<v8::Value> value) | |
1250 { | |
1251 v8::Handle<v8::String> string = value.As<v8::String>(); | |
1252 if (!string->Length() || string->IsOneByte()) | |
1253 m_writer.writeOneByteString(string); | |
1254 else | |
1255 m_writer.writeUCharString(string); | |
1256 } | |
1257 | |
1258 void writeStringObject(v8::Handle<v8::Value> value) | |
1259 { | |
1260 v8::Handle<v8::StringObject> stringObject = value.As<v8::StringObject>()
; | |
1261 v8::String::Utf8Value stringValue(stringObject->ValueOf()); | |
1262 m_writer.writeStringObject(*stringValue, stringValue.length()); | |
1263 } | |
1264 | |
1265 void writeNumberObject(v8::Handle<v8::Value> value) | |
1266 { | |
1267 v8::Handle<v8::NumberObject> numberObject = value.As<v8::NumberObject>()
; | |
1268 m_writer.writeNumberObject(numberObject->ValueOf()); | |
1269 } | |
1270 | |
1271 void writeBooleanObject(v8::Handle<v8::Value> value) | |
1272 { | |
1273 v8::Handle<v8::BooleanObject> booleanObject = value.As<v8::BooleanObject
>(); | |
1274 m_writer.writeBooleanObject(booleanObject->ValueOf()); | |
1275 } | |
1276 | |
1277 StateBase* writeBlob(v8::Handle<v8::Value> value, StateBase* next) | |
1278 { | |
1279 Blob* blob = V8Blob::toNative(value.As<v8::Object>()); | |
1280 if (!blob) | |
1281 return 0; | |
1282 if (blob->hasBeenClosed()) | |
1283 return handleError(DataCloneError, "A Blob object has been closed, a
nd could therefore not be cloned.", next); | |
1284 int blobIndex = -1; | |
1285 m_blobDataHandles.add(blob->uuid(), blob->blobDataHandle()); | |
1286 if (appendBlobInfo(blob->uuid(), blob->type(), blob->size(), &blobIndex)
) | |
1287 m_writer.writeBlobIndex(blobIndex); | |
1288 else | |
1289 m_writer.writeBlob(blob->uuid(), blob->type(), blob->size()); | |
1290 return 0; | |
1291 } | |
1292 | |
1293 StateBase* writeDOMFileSystem(v8::Handle<v8::Value> value, StateBase* next) | |
1294 { | |
1295 DOMFileSystem* fs = V8DOMFileSystem::toNative(value.As<v8::Object>()); | |
1296 if (!fs) | |
1297 return 0; | |
1298 if (!fs->clonable()) | |
1299 return handleError(DataCloneError, "A FileSystem object could not be
cloned.", next); | |
1300 m_writer.writeDOMFileSystem(fs->type(), fs->name(), fs->rootURL().string
()); | |
1301 return 0; | |
1302 } | |
1303 | |
1304 StateBase* writeFile(v8::Handle<v8::Value> value, StateBase* next) | |
1305 { | |
1306 File* file = V8File::toNative(value.As<v8::Object>()); | |
1307 if (!file) | |
1308 return 0; | |
1309 if (file->hasBeenClosed()) | |
1310 return handleError(DataCloneError, "A File object has been closed, a
nd could therefore not be cloned.", next); | |
1311 int blobIndex = -1; | |
1312 m_blobDataHandles.add(file->uuid(), file->blobDataHandle()); | |
1313 if (appendFileInfo(file, &blobIndex)) { | |
1314 ASSERT(blobIndex >= 0); | |
1315 m_writer.writeFileIndex(blobIndex); | |
1316 } else { | |
1317 m_writer.writeFile(*file); | |
1318 } | |
1319 return 0; | |
1320 } | |
1321 | |
1322 StateBase* writeFileList(v8::Handle<v8::Value> value, StateBase* next) | |
1323 { | |
1324 FileList* fileList = V8FileList::toNative(value.As<v8::Object>()); | |
1325 if (!fileList) | |
1326 return 0; | |
1327 unsigned length = fileList->length(); | |
1328 Vector<int> blobIndices; | |
1329 for (unsigned i = 0; i < length; ++i) { | |
1330 int blobIndex = -1; | |
1331 const File* file = fileList->item(i); | |
1332 if (file->hasBeenClosed()) | |
1333 return handleError(DataCloneError, "A File object has been close
d, and could therefore not be cloned.", next); | |
1334 m_blobDataHandles.add(file->uuid(), file->blobDataHandle()); | |
1335 if (appendFileInfo(file, &blobIndex)) { | |
1336 ASSERT(!i || blobIndex > 0); | |
1337 ASSERT(blobIndex >= 0); | |
1338 blobIndices.append(blobIndex); | |
1339 } | |
1340 } | |
1341 if (!blobIndices.isEmpty()) | |
1342 m_writer.writeFileListIndex(blobIndices); | |
1343 else | |
1344 m_writer.writeFileList(*fileList); | |
1345 return 0; | |
1346 } | |
1347 | |
1348 bool writeCryptoKey(v8::Handle<v8::Value> value) | |
1349 { | |
1350 CryptoKey* key = V8CryptoKey::toNative(value.As<v8::Object>()); | |
1351 if (!key) | |
1352 return false; | |
1353 return m_writer.writeCryptoKey(key->key()); | |
1354 } | |
1355 | |
1356 void writeImageData(v8::Handle<v8::Value> value) | |
1357 { | |
1358 ImageData* imageData = V8ImageData::toNative(value.As<v8::Object>()); | |
1359 if (!imageData) | |
1360 return; | |
1361 Uint8ClampedArray* pixelArray = imageData->data(); | |
1362 m_writer.writeImageData(imageData->width(), imageData->height(), pixelAr
ray->data(), pixelArray->length()); | |
1363 } | |
1364 | |
1365 void writeRegExp(v8::Handle<v8::Value> value) | |
1366 { | |
1367 v8::Handle<v8::RegExp> regExp = value.As<v8::RegExp>(); | |
1368 m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags()); | |
1369 } | |
1370 | |
1371 StateBase* writeAndGreyArrayBufferView(v8::Handle<v8::Object> object, StateB
ase* next) | |
1372 { | |
1373 ASSERT(!object.IsEmpty()); | |
1374 ArrayBufferView* arrayBufferView = V8ArrayBufferView::toNative(object); | |
1375 if (!arrayBufferView) | |
1376 return 0; | |
1377 if (!arrayBufferView->buffer()) | |
1378 return handleError(DataCloneError, "An ArrayBuffer could not be clon
ed.", next); | |
1379 v8::Handle<v8::Value> underlyingBuffer = toV8(arrayBufferView->buffer(),
m_scriptState->context()->Global(), isolate()); | |
1380 if (underlyingBuffer.IsEmpty()) | |
1381 return handleError(DataCloneError, "An ArrayBuffer could not be clon
ed.", next); | |
1382 StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next); | |
1383 if (stateOut) | |
1384 return stateOut; | |
1385 m_writer.writeArrayBufferView(*arrayBufferView); | |
1386 // This should be safe: we serialize something that we know to be a wrap
per (see | |
1387 // the toV8 call above), so the call to doSerializeArrayBuffer should ne
ither | |
1388 // cause the system stack to overflow nor should it have potential to re
ach | |
1389 // this ArrayBufferView again. | |
1390 // | |
1391 // We do need to grey the underlying buffer before we grey its view, how
ever; | |
1392 // ArrayBuffers may be shared, so they need to be given reference IDs, a
nd an | |
1393 // ArrayBufferView cannot be constructed without a corresponding ArrayBu
ffer | |
1394 // (or without an additional tag that would allow us to do two-stage con
struction | |
1395 // like we do for Objects and Arrays). | |
1396 greyObject(object); | |
1397 return 0; | |
1398 } | |
1399 | |
1400 StateBase* writeArrayBuffer(v8::Handle<v8::Value> value, StateBase* next) | |
1401 { | |
1402 ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(value.As<v8::Object>(
)); | |
1403 if (!arrayBuffer) | |
1404 return 0; | |
1405 if (arrayBuffer->isNeutered()) | |
1406 return handleError(DataCloneError, "An ArrayBuffer is neutered and c
ould not be cloned.", next); | |
1407 ASSERT(!m_transferredArrayBuffers.contains(value.As<v8::Object>())); | |
1408 m_writer.writeArrayBuffer(*arrayBuffer); | |
1409 return 0; | |
1410 } | |
1411 | |
1412 StateBase* writeTransferredArrayBuffer(v8::Handle<v8::Value> value, uint32_t
index, StateBase* next) | |
1413 { | |
1414 ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(value.As<v8::Object>(
)); | |
1415 if (!arrayBuffer) | |
1416 return 0; | |
1417 if (arrayBuffer->isNeutered()) | |
1418 return handleError(DataCloneError, "An ArrayBuffer is neutered and c
ould not be cloned.", next); | |
1419 m_writer.writeTransferredArrayBuffer(index); | |
1420 return 0; | |
1421 } | |
1422 | |
1423 static bool shouldSerializeDensely(uint32_t length, uint32_t propertyCount) | |
1424 { | |
1425 // Let K be the cost of serializing all property values that are there | |
1426 // Cost of serializing sparsely: 5*propertyCount + K (5 bytes per uint32
_t key) | |
1427 // Cost of serializing densely: K + 1*(length - propertyCount) (1 byte f
or all properties that are not there) | |
1428 // so densely is better than sparsly whenever 6*propertyCount > length | |
1429 return 6 * propertyCount >= length; | |
1430 } | |
1431 | |
1432 StateBase* startArrayState(v8::Handle<v8::Array> array, StateBase* next) | |
1433 { | |
1434 v8::Handle<v8::Array> propertyNames = array->GetPropertyNames(); | |
1435 if (StateBase* newState = checkException(next)) | |
1436 return newState; | |
1437 uint32_t length = array->Length(); | |
1438 | |
1439 if (shouldSerializeDensely(length, propertyNames->Length())) { | |
1440 m_writer.writeGenerateFreshDenseArray(length); | |
1441 return push(new DenseArrayState(array, propertyNames, next, isolate(
))); | |
1442 } | |
1443 | |
1444 m_writer.writeGenerateFreshSparseArray(length); | |
1445 return push(new SparseArrayState(array, propertyNames, next, isolate()))
; | |
1446 } | |
1447 | |
1448 StateBase* startObjectState(v8::Handle<v8::Object> object, StateBase* next) | |
1449 { | |
1450 m_writer.writeGenerateFreshObject(); | |
1451 // FIXME: check not a wrapper | |
1452 return push(new ObjectState(object, next)); | |
1453 } | |
1454 | |
1455 // Marks object as having been visited by the serializer and assigns it a un
ique object reference ID. | |
1456 // An object may only be greyed once. | |
1457 void greyObject(const v8::Handle<v8::Object>& object) | |
1458 { | |
1459 ASSERT(!m_objectPool.contains(object)); | |
1460 uint32_t objectReference = m_nextObjectReference++; | |
1461 m_objectPool.set(object, objectReference); | |
1462 } | |
1463 | |
1464 bool appendBlobInfo(const String& uuid, const String& type, unsigned long lo
ng size, int* index) | |
1465 { | |
1466 if (!m_blobInfo) | |
1467 return false; | |
1468 *index = m_blobInfo->size(); | |
1469 m_blobInfo->append(blink::WebBlobInfo(uuid, type, size)); | |
1470 return true; | |
1471 } | |
1472 | |
1473 bool appendFileInfo(const File* file, int* index) | |
1474 { | |
1475 if (!m_blobInfo) | |
1476 return false; | |
1477 | |
1478 long long size = -1; | |
1479 double lastModified = invalidFileTime(); | |
1480 file->captureSnapshot(size, lastModified); | |
1481 *index = m_blobInfo->size(); | |
1482 m_blobInfo->append(blink::WebBlobInfo(file->uuid(), file->path(), file->
name(), file->type(), lastModified, size)); | |
1483 return true; | |
1484 } | |
1485 | |
1486 RefPtr<ScriptState> m_scriptState; | |
1487 Writer& m_writer; | |
1488 v8::TryCatch& m_tryCatch; | |
1489 int m_depth; | |
1490 Status m_status; | |
1491 String m_errorMessage; | |
1492 typedef V8ObjectMap<v8::Object, uint32_t> ObjectPool; | |
1493 ObjectPool m_objectPool; | |
1494 ObjectPool m_transferredMessagePorts; | |
1495 ObjectPool m_transferredArrayBuffers; | |
1496 uint32_t m_nextObjectReference; | |
1497 WebBlobInfoArray* m_blobInfo; | |
1498 BlobDataHandleMap& m_blobDataHandles; | |
1499 }; | |
1500 | |
1501 // Returns true if the provided object is to be considered a 'host object', as u
sed in the | |
1502 // HTML5 structured clone algorithm. | |
1503 static bool isHostObject(v8::Handle<v8::Object> object) | |
1504 { | |
1505 // If the object has any internal fields, then we won't be able to serialize
or deserialize | |
1506 // them; conveniently, this is also a quick way to detect DOM wrapper object
s, because | |
1507 // the mechanism for these relies on data stored in these fields. We should | |
1508 // catch external array data as a special case. | |
1509 return object->InternalFieldCount() || object->HasIndexedPropertiesInExterna
lArrayData(); | |
1510 } | |
1511 | |
1512 Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Stat
eBase* next) | |
1513 { | |
1514 m_writer.writeReferenceCount(m_nextObjectReference); | |
1515 uint32_t objectReference; | |
1516 uint32_t arrayBufferIndex; | |
1517 if ((value->IsObject() || value->IsDate() || value->IsRegExp()) | |
1518 && m_objectPool.tryGet(value.As<v8::Object>(), &objectReference)) { | |
1519 // Note that IsObject() also detects wrappers (eg, it will catch the thi
ngs | |
1520 // that we grey and write below). | |
1521 ASSERT(!value->IsString()); | |
1522 m_writer.writeObjectReference(objectReference); | |
1523 } else if (value.IsEmpty()) { | |
1524 return handleError(InputError, "The empty property name cannot be cloned
.", next); | |
1525 } else if (value->IsUndefined()) | |
1526 m_writer.writeUndefined(); | |
1527 else if (value->IsNull()) | |
1528 m_writer.writeNull(); | |
1529 else if (value->IsTrue()) | |
1530 m_writer.writeTrue(); | |
1531 else if (value->IsFalse()) | |
1532 m_writer.writeFalse(); | |
1533 else if (value->IsInt32()) | |
1534 m_writer.writeInt32(value->Int32Value()); | |
1535 else if (value->IsUint32()) | |
1536 m_writer.writeUint32(value->Uint32Value()); | |
1537 else if (value->IsNumber()) | |
1538 m_writer.writeNumber(value.As<v8::Number>()->Value()); | |
1539 else if (V8ArrayBufferView::hasInstance(value, isolate())) | |
1540 return writeAndGreyArrayBufferView(value.As<v8::Object>(), next); | |
1541 else if (value->IsString()) | |
1542 writeString(value); | |
1543 else if (V8MessagePort::hasInstance(value, isolate())) { | |
1544 uint32_t messagePortIndex; | |
1545 if (m_transferredMessagePorts.tryGet(value.As<v8::Object>(), &messagePor
tIndex)) | |
1546 m_writer.writeTransferredMessagePort(messagePortIndex); | |
1547 else | |
1548 return handleError(DataCloneError, "A MessagePort could not be c
loned.", next); | |
1549 } else if (V8ArrayBuffer::hasInstance(value, isolate()) && m_transferredArra
yBuffers.tryGet(value.As<v8::Object>(), &arrayBufferIndex)) | |
1550 return writeTransferredArrayBuffer(value, arrayBufferIndex, next); | |
1551 else { | |
1552 v8::Handle<v8::Object> jsObject = value.As<v8::Object>(); | |
1553 if (jsObject.IsEmpty()) | |
1554 return handleError(DataCloneError, "An object could not be cloned.",
next); | |
1555 greyObject(jsObject); | |
1556 if (value->IsDate()) | |
1557 m_writer.writeDate(value->NumberValue()); | |
1558 else if (value->IsStringObject()) | |
1559 writeStringObject(value); | |
1560 else if (value->IsNumberObject()) | |
1561 writeNumberObject(value); | |
1562 else if (value->IsBooleanObject()) | |
1563 writeBooleanObject(value); | |
1564 else if (value->IsArray()) { | |
1565 return startArrayState(value.As<v8::Array>(), next); | |
1566 } else if (V8File::hasInstance(value, isolate())) | |
1567 return writeFile(value, next); | |
1568 else if (V8Blob::hasInstance(value, isolate())) | |
1569 return writeBlob(value, next); | |
1570 else if (V8DOMFileSystem::hasInstance(value, isolate())) | |
1571 return writeDOMFileSystem(value, next); | |
1572 else if (V8FileList::hasInstance(value, isolate())) | |
1573 return writeFileList(value, next); | |
1574 else if (V8CryptoKey::hasInstance(value, isolate())) { | |
1575 if (!writeCryptoKey(value)) | |
1576 return handleError(DataCloneError, "Couldn't serialize key data"
, next); | |
1577 } else if (V8ImageData::hasInstance(value, isolate())) | |
1578 writeImageData(value); | |
1579 else if (value->IsRegExp()) | |
1580 writeRegExp(value); | |
1581 else if (V8ArrayBuffer::hasInstance(value, isolate())) | |
1582 return writeArrayBuffer(value, next); | |
1583 else if (value->IsObject()) { | |
1584 if (isHostObject(jsObject) || jsObject->IsCallable() || value->IsNat
iveError()) | |
1585 return handleError(DataCloneError, "An object could not be clone
d.", next); | |
1586 return startObjectState(jsObject, next); | |
1587 } else | |
1588 return handleError(DataCloneError, "A value could not be cloned.", n
ext); | |
1589 } | |
1590 return 0; | |
1591 } | |
1592 | |
1593 // Interface used by Reader to create objects of composite types. | |
1594 class CompositeCreator { | |
1595 public: | |
1596 virtual ~CompositeCreator() { } | |
1597 | |
1598 virtual bool consumeTopOfStack(v8::Handle<v8::Value>*) = 0; | |
1599 virtual uint32_t objectReferenceCount() = 0; | |
1600 virtual void pushObjectReference(const v8::Handle<v8::Value>&) = 0; | |
1601 virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<
v8::Value>*) = 0; | |
1602 virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Val
ue>*) = 0; | |
1603 virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Val
ue>*) = 0; | |
1604 virtual bool newSparseArray(uint32_t length) = 0; | |
1605 virtual bool newDenseArray(uint32_t length) = 0; | |
1606 virtual bool newObject() = 0; | |
1607 virtual bool completeObject(uint32_t numProperties, v8::Handle<v8::Value>*)
= 0; | |
1608 virtual bool completeSparseArray(uint32_t numProperties, uint32_t length, v8
::Handle<v8::Value>*) = 0; | |
1609 virtual bool completeDenseArray(uint32_t numProperties, uint32_t length, v8:
:Handle<v8::Value>*) = 0; | |
1610 }; | |
1611 | |
1612 // Reader is responsible for deserializing primitive types and | |
1613 // restoring information about saved objects of composite types. | |
1614 class Reader { | |
1615 public: | |
1616 Reader(const uint8_t* buffer, int length, const WebBlobInfoArray* blobInfo,
BlobDataHandleMap& blobDataHandles, ScriptState* scriptState) | |
1617 : m_scriptState(scriptState) | |
1618 , m_buffer(buffer) | |
1619 , m_length(length) | |
1620 , m_position(0) | |
1621 , m_version(0) | |
1622 , m_blobInfo(blobInfo) | |
1623 , m_blobDataHandles(blobDataHandles) | |
1624 { | |
1625 ASSERT(!(reinterpret_cast<size_t>(buffer) & 1)); | |
1626 ASSERT(length >= 0); | |
1627 } | |
1628 | |
1629 bool isEof() const { return m_position >= m_length; } | |
1630 | |
1631 ScriptState* scriptState() const { return m_scriptState.get(); } | |
1632 | |
1633 private: | |
1634 v8::Isolate* isolate() const { return m_scriptState->isolate(); } | |
1635 | |
1636 public: | |
1637 bool read(v8::Handle<v8::Value>* value, CompositeCreator& creator) | |
1638 { | |
1639 SerializationTag tag; | |
1640 if (!readTag(&tag)) | |
1641 return false; | |
1642 switch (tag) { | |
1643 case ReferenceCountTag: { | |
1644 if (!m_version) | |
1645 return false; | |
1646 uint32_t referenceTableSize; | |
1647 if (!doReadUint32(&referenceTableSize)) | |
1648 return false; | |
1649 // If this test fails, then the serializer and deserializer disagree
about the assignment | |
1650 // of object reference IDs. On the deserialization side, this means
there are too many or too few | |
1651 // calls to pushObjectReference. | |
1652 if (referenceTableSize != creator.objectReferenceCount()) | |
1653 return false; | |
1654 return true; | |
1655 } | |
1656 case InvalidTag: | |
1657 return false; | |
1658 case PaddingTag: | |
1659 return true; | |
1660 case UndefinedTag: | |
1661 *value = v8::Undefined(isolate()); | |
1662 break; | |
1663 case NullTag: | |
1664 *value = v8::Null(isolate()); | |
1665 break; | |
1666 case TrueTag: | |
1667 *value = v8Boolean(true, isolate()); | |
1668 break; | |
1669 case FalseTag: | |
1670 *value = v8Boolean(false, isolate()); | |
1671 break; | |
1672 case TrueObjectTag: | |
1673 *value = v8::BooleanObject::New(true); | |
1674 creator.pushObjectReference(*value); | |
1675 break; | |
1676 case FalseObjectTag: | |
1677 *value = v8::BooleanObject::New(false); | |
1678 creator.pushObjectReference(*value); | |
1679 break; | |
1680 case StringTag: | |
1681 if (!readString(value)) | |
1682 return false; | |
1683 break; | |
1684 case StringUCharTag: | |
1685 if (!readUCharString(value)) | |
1686 return false; | |
1687 break; | |
1688 case StringObjectTag: | |
1689 if (!readStringObject(value)) | |
1690 return false; | |
1691 creator.pushObjectReference(*value); | |
1692 break; | |
1693 case Int32Tag: | |
1694 if (!readInt32(value)) | |
1695 return false; | |
1696 break; | |
1697 case Uint32Tag: | |
1698 if (!readUint32(value)) | |
1699 return false; | |
1700 break; | |
1701 case DateTag: | |
1702 if (!readDate(value)) | |
1703 return false; | |
1704 creator.pushObjectReference(*value); | |
1705 break; | |
1706 case NumberTag: | |
1707 if (!readNumber(value)) | |
1708 return false; | |
1709 break; | |
1710 case NumberObjectTag: | |
1711 if (!readNumberObject(value)) | |
1712 return false; | |
1713 creator.pushObjectReference(*value); | |
1714 break; | |
1715 case BlobTag: | |
1716 case BlobIndexTag: | |
1717 if (!readBlob(value, tag == BlobIndexTag)) | |
1718 return false; | |
1719 creator.pushObjectReference(*value); | |
1720 break; | |
1721 case FileTag: | |
1722 case FileIndexTag: | |
1723 if (!readFile(value, tag == FileIndexTag)) | |
1724 return false; | |
1725 creator.pushObjectReference(*value); | |
1726 break; | |
1727 case DOMFileSystemTag: | |
1728 if (!readDOMFileSystem(value)) | |
1729 return false; | |
1730 creator.pushObjectReference(*value); | |
1731 break; | |
1732 case FileListTag: | |
1733 case FileListIndexTag: | |
1734 if (!readFileList(value, tag == FileListIndexTag)) | |
1735 return false; | |
1736 creator.pushObjectReference(*value); | |
1737 break; | |
1738 case CryptoKeyTag: | |
1739 if (!readCryptoKey(value)) | |
1740 return false; | |
1741 creator.pushObjectReference(*value); | |
1742 break; | |
1743 case ImageDataTag: | |
1744 if (!readImageData(value)) | |
1745 return false; | |
1746 creator.pushObjectReference(*value); | |
1747 break; | |
1748 | |
1749 case RegExpTag: | |
1750 if (!readRegExp(value)) | |
1751 return false; | |
1752 creator.pushObjectReference(*value); | |
1753 break; | |
1754 case ObjectTag: { | |
1755 uint32_t numProperties; | |
1756 if (!doReadUint32(&numProperties)) | |
1757 return false; | |
1758 if (!creator.completeObject(numProperties, value)) | |
1759 return false; | |
1760 break; | |
1761 } | |
1762 case SparseArrayTag: { | |
1763 uint32_t numProperties; | |
1764 uint32_t length; | |
1765 if (!doReadUint32(&numProperties)) | |
1766 return false; | |
1767 if (!doReadUint32(&length)) | |
1768 return false; | |
1769 if (!creator.completeSparseArray(numProperties, length, value)) | |
1770 return false; | |
1771 break; | |
1772 } | |
1773 case DenseArrayTag: { | |
1774 uint32_t numProperties; | |
1775 uint32_t length; | |
1776 if (!doReadUint32(&numProperties)) | |
1777 return false; | |
1778 if (!doReadUint32(&length)) | |
1779 return false; | |
1780 if (!creator.completeDenseArray(numProperties, length, value)) | |
1781 return false; | |
1782 break; | |
1783 } | |
1784 case ArrayBufferViewTag: { | |
1785 if (!m_version) | |
1786 return false; | |
1787 if (!readArrayBufferView(value, creator)) | |
1788 return false; | |
1789 creator.pushObjectReference(*value); | |
1790 break; | |
1791 } | |
1792 case ArrayBufferTag: { | |
1793 if (!m_version) | |
1794 return false; | |
1795 if (!readArrayBuffer(value)) | |
1796 return false; | |
1797 creator.pushObjectReference(*value); | |
1798 break; | |
1799 } | |
1800 case GenerateFreshObjectTag: { | |
1801 if (!m_version) | |
1802 return false; | |
1803 if (!creator.newObject()) | |
1804 return false; | |
1805 return true; | |
1806 } | |
1807 case GenerateFreshSparseArrayTag: { | |
1808 if (!m_version) | |
1809 return false; | |
1810 uint32_t length; | |
1811 if (!doReadUint32(&length)) | |
1812 return false; | |
1813 if (!creator.newSparseArray(length)) | |
1814 return false; | |
1815 return true; | |
1816 } | |
1817 case GenerateFreshDenseArrayTag: { | |
1818 if (!m_version) | |
1819 return false; | |
1820 uint32_t length; | |
1821 if (!doReadUint32(&length)) | |
1822 return false; | |
1823 if (!creator.newDenseArray(length)) | |
1824 return false; | |
1825 return true; | |
1826 } | |
1827 case MessagePortTag: { | |
1828 if (!m_version) | |
1829 return false; | |
1830 uint32_t index; | |
1831 if (!doReadUint32(&index)) | |
1832 return false; | |
1833 if (!creator.tryGetTransferredMessagePort(index, value)) | |
1834 return false; | |
1835 break; | |
1836 } | |
1837 case ArrayBufferTransferTag: { | |
1838 if (!m_version) | |
1839 return false; | |
1840 uint32_t index; | |
1841 if (!doReadUint32(&index)) | |
1842 return false; | |
1843 if (!creator.tryGetTransferredArrayBuffer(index, value)) | |
1844 return false; | |
1845 break; | |
1846 } | |
1847 case ObjectReferenceTag: { | |
1848 if (!m_version) | |
1849 return false; | |
1850 uint32_t reference; | |
1851 if (!doReadUint32(&reference)) | |
1852 return false; | |
1853 if (!creator.tryGetObjectFromObjectReference(reference, value)) | |
1854 return false; | |
1855 break; | |
1856 } | |
1857 default: | |
1858 return false; | |
1859 } | |
1860 return !value->IsEmpty(); | |
1861 } | |
1862 | |
1863 bool readVersion(uint32_t& version) | |
1864 { | |
1865 SerializationTag tag; | |
1866 if (!readTag(&tag)) { | |
1867 // This is a nullary buffer. We're still version 0. | |
1868 version = 0; | |
1869 return true; | |
1870 } | |
1871 if (tag != VersionTag) { | |
1872 // Versions of the format past 0 start with the version tag. | |
1873 version = 0; | |
1874 // Put back the tag. | |
1875 undoReadTag(); | |
1876 return true; | |
1877 } | |
1878 // Version-bearing messages are obligated to finish the version tag. | |
1879 return doReadUint32(&version); | |
1880 } | |
1881 | |
1882 void setVersion(uint32_t version) | |
1883 { | |
1884 m_version = version; | |
1885 } | |
1886 | |
1887 private: | |
1888 bool readTag(SerializationTag* tag) | |
1889 { | |
1890 if (m_position >= m_length) | |
1891 return false; | |
1892 *tag = static_cast<SerializationTag>(m_buffer[m_position++]); | |
1893 return true; | |
1894 } | |
1895 | |
1896 void undoReadTag() | |
1897 { | |
1898 if (m_position > 0) | |
1899 --m_position; | |
1900 } | |
1901 | |
1902 bool readArrayBufferViewSubTag(ArrayBufferViewSubTag* tag) | |
1903 { | |
1904 if (m_position >= m_length) | |
1905 return false; | |
1906 *tag = static_cast<ArrayBufferViewSubTag>(m_buffer[m_position++]); | |
1907 return true; | |
1908 } | |
1909 | |
1910 bool readString(v8::Handle<v8::Value>* value) | |
1911 { | |
1912 uint32_t length; | |
1913 if (!doReadUint32(&length)) | |
1914 return false; | |
1915 if (m_position + length > m_length) | |
1916 return false; | |
1917 *value = v8::String::NewFromUtf8(isolate(), reinterpret_cast<const char*
>(m_buffer + m_position), v8::String::kNormalString, length); | |
1918 m_position += length; | |
1919 return true; | |
1920 } | |
1921 | |
1922 bool readUCharString(v8::Handle<v8::Value>* value) | |
1923 { | |
1924 uint32_t length; | |
1925 if (!doReadUint32(&length) || (length & 1)) | |
1926 return false; | |
1927 if (m_position + length > m_length) | |
1928 return false; | |
1929 ASSERT(!(m_position & 1)); | |
1930 *value = v8::String::NewFromTwoByte(isolate(), reinterpret_cast<const ui
nt16_t*>(m_buffer + m_position), v8::String::kNormalString, length / sizeof(UCha
r)); | |
1931 m_position += length; | |
1932 return true; | |
1933 } | |
1934 | |
1935 bool readStringObject(v8::Handle<v8::Value>* value) | |
1936 { | |
1937 v8::Handle<v8::Value> stringValue; | |
1938 if (!readString(&stringValue) || !stringValue->IsString()) | |
1939 return false; | |
1940 *value = v8::StringObject::New(stringValue.As<v8::String>()); | |
1941 return true; | |
1942 } | |
1943 | |
1944 bool readWebCoreString(String* string) | |
1945 { | |
1946 uint32_t length; | |
1947 if (!doReadUint32(&length)) | |
1948 return false; | |
1949 if (m_position + length > m_length) | |
1950 return false; | |
1951 *string = String::fromUTF8(reinterpret_cast<const char*>(m_buffer + m_po
sition), length); | |
1952 m_position += length; | |
1953 return true; | |
1954 } | |
1955 | |
1956 bool readInt32(v8::Handle<v8::Value>* value) | |
1957 { | |
1958 uint32_t rawValue; | |
1959 if (!doReadUint32(&rawValue)) | |
1960 return false; | |
1961 *value = v8::Integer::New(isolate(), static_cast<int32_t>(ZigZag::decode
(rawValue))); | |
1962 return true; | |
1963 } | |
1964 | |
1965 bool readUint32(v8::Handle<v8::Value>* value) | |
1966 { | |
1967 uint32_t rawValue; | |
1968 if (!doReadUint32(&rawValue)) | |
1969 return false; | |
1970 *value = v8::Integer::NewFromUnsigned(isolate(), rawValue); | |
1971 return true; | |
1972 } | |
1973 | |
1974 bool readDate(v8::Handle<v8::Value>* value) | |
1975 { | |
1976 double numberValue; | |
1977 if (!doReadNumber(&numberValue)) | |
1978 return false; | |
1979 *value = v8DateOrNaN(numberValue, isolate()); | |
1980 return true; | |
1981 } | |
1982 | |
1983 bool readNumber(v8::Handle<v8::Value>* value) | |
1984 { | |
1985 double number; | |
1986 if (!doReadNumber(&number)) | |
1987 return false; | |
1988 *value = v8::Number::New(isolate(), number); | |
1989 return true; | |
1990 } | |
1991 | |
1992 bool readNumberObject(v8::Handle<v8::Value>* value) | |
1993 { | |
1994 double number; | |
1995 if (!doReadNumber(&number)) | |
1996 return false; | |
1997 *value = v8::NumberObject::New(isolate(), number); | |
1998 return true; | |
1999 } | |
2000 | |
2001 bool readImageData(v8::Handle<v8::Value>* value) | |
2002 { | |
2003 uint32_t width; | |
2004 uint32_t height; | |
2005 uint32_t pixelDataLength; | |
2006 if (!doReadUint32(&width)) | |
2007 return false; | |
2008 if (!doReadUint32(&height)) | |
2009 return false; | |
2010 if (!doReadUint32(&pixelDataLength)) | |
2011 return false; | |
2012 if (m_position + pixelDataLength > m_length) | |
2013 return false; | |
2014 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(IntSize(widt
h, height)); | |
2015 Uint8ClampedArray* pixelArray = imageData->data(); | |
2016 ASSERT(pixelArray); | |
2017 ASSERT(pixelArray->length() >= pixelDataLength); | |
2018 memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength); | |
2019 m_position += pixelDataLength; | |
2020 *value = toV8(imageData.release(), m_scriptState->context()->Global(), i
solate()); | |
2021 return true; | |
2022 } | |
2023 | |
2024 PassRefPtr<ArrayBuffer> doReadArrayBuffer() | |
2025 { | |
2026 uint32_t byteLength; | |
2027 if (!doReadUint32(&byteLength)) | |
2028 return nullptr; | |
2029 if (m_position + byteLength > m_length) | |
2030 return nullptr; | |
2031 const void* bufferStart = m_buffer + m_position; | |
2032 RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::create(bufferStart, byteL
ength); | |
2033 arrayBuffer->setDeallocationObserver(V8ArrayBufferDeallocationObserver::
instanceTemplate()); | |
2034 m_position += byteLength; | |
2035 return arrayBuffer.release(); | |
2036 } | |
2037 | |
2038 bool readArrayBuffer(v8::Handle<v8::Value>* value) | |
2039 { | |
2040 RefPtr<ArrayBuffer> arrayBuffer = doReadArrayBuffer(); | |
2041 if (!arrayBuffer) | |
2042 return false; | |
2043 *value = toV8(arrayBuffer.release(), m_scriptState->context()->Global(),
isolate()); | |
2044 return true; | |
2045 } | |
2046 | |
2047 bool readArrayBufferView(v8::Handle<v8::Value>* value, CompositeCreator& cre
ator) | |
2048 { | |
2049 ArrayBufferViewSubTag subTag; | |
2050 uint32_t byteOffset; | |
2051 uint32_t byteLength; | |
2052 RefPtr<ArrayBuffer> arrayBuffer; | |
2053 v8::Handle<v8::Value> arrayBufferV8Value; | |
2054 if (!readArrayBufferViewSubTag(&subTag)) | |
2055 return false; | |
2056 if (!doReadUint32(&byteOffset)) | |
2057 return false; | |
2058 if (!doReadUint32(&byteLength)) | |
2059 return false; | |
2060 if (!creator.consumeTopOfStack(&arrayBufferV8Value)) | |
2061 return false; | |
2062 if (arrayBufferV8Value.IsEmpty()) | |
2063 return false; | |
2064 arrayBuffer = V8ArrayBuffer::toNative(arrayBufferV8Value.As<v8::Object>(
)); | |
2065 if (!arrayBuffer) | |
2066 return false; | |
2067 | |
2068 v8::Handle<v8::Object> creationContext = m_scriptState->context()->Globa
l(); | |
2069 switch (subTag) { | |
2070 case ByteArrayTag: | |
2071 *value = toV8(Int8Array::create(arrayBuffer.release(), byteOffset, b
yteLength), creationContext, isolate()); | |
2072 break; | |
2073 case UnsignedByteArrayTag: | |
2074 *value = toV8(Uint8Array::create(arrayBuffer.release(), byteOffset,
byteLength), creationContext, isolate()); | |
2075 break; | |
2076 case UnsignedByteClampedArrayTag: | |
2077 *value = toV8(Uint8ClampedArray::create(arrayBuffer.release(), byteO
ffset, byteLength), creationContext, isolate()); | |
2078 break; | |
2079 case ShortArrayTag: { | |
2080 uint32_t shortLength = byteLength / sizeof(int16_t); | |
2081 if (shortLength * sizeof(int16_t) != byteLength) | |
2082 return false; | |
2083 *value = toV8(Int16Array::create(arrayBuffer.release(), byteOffset,
shortLength), creationContext, isolate()); | |
2084 break; | |
2085 } | |
2086 case UnsignedShortArrayTag: { | |
2087 uint32_t shortLength = byteLength / sizeof(uint16_t); | |
2088 if (shortLength * sizeof(uint16_t) != byteLength) | |
2089 return false; | |
2090 *value = toV8(Uint16Array::create(arrayBuffer.release(), byteOffset,
shortLength), creationContext, isolate()); | |
2091 break; | |
2092 } | |
2093 case IntArrayTag: { | |
2094 uint32_t intLength = byteLength / sizeof(int32_t); | |
2095 if (intLength * sizeof(int32_t) != byteLength) | |
2096 return false; | |
2097 *value = toV8(Int32Array::create(arrayBuffer.release(), byteOffset,
intLength), creationContext, isolate()); | |
2098 break; | |
2099 } | |
2100 case UnsignedIntArrayTag: { | |
2101 uint32_t intLength = byteLength / sizeof(uint32_t); | |
2102 if (intLength * sizeof(uint32_t) != byteLength) | |
2103 return false; | |
2104 *value = toV8(Uint32Array::create(arrayBuffer.release(), byteOffset,
intLength), creationContext, isolate()); | |
2105 break; | |
2106 } | |
2107 case FloatArrayTag: { | |
2108 uint32_t floatLength = byteLength / sizeof(float); | |
2109 if (floatLength * sizeof(float) != byteLength) | |
2110 return false; | |
2111 *value = toV8(Float32Array::create(arrayBuffer.release(), byteOffset
, floatLength), creationContext, isolate()); | |
2112 break; | |
2113 } | |
2114 case DoubleArrayTag: { | |
2115 uint32_t floatLength = byteLength / sizeof(double); | |
2116 if (floatLength * sizeof(double) != byteLength) | |
2117 return false; | |
2118 *value = toV8(Float64Array::create(arrayBuffer.release(), byteOffset
, floatLength), creationContext, isolate()); | |
2119 break; | |
2120 } | |
2121 case DataViewTag: | |
2122 *value = toV8(DataView::create(arrayBuffer.release(), byteOffset, by
teLength), creationContext, isolate()); | |
2123 break; | |
2124 default: | |
2125 return false; | |
2126 } | |
2127 // The various *Array::create() methods will return null if the range th
e view expects is | |
2128 // mismatched with the range the buffer can provide or if the byte offse
t is not aligned | |
2129 // to the size of the element type. | |
2130 return !value->IsEmpty(); | |
2131 } | |
2132 | |
2133 bool readRegExp(v8::Handle<v8::Value>* value) | |
2134 { | |
2135 v8::Handle<v8::Value> pattern; | |
2136 if (!readString(&pattern)) | |
2137 return false; | |
2138 uint32_t flags; | |
2139 if (!doReadUint32(&flags)) | |
2140 return false; | |
2141 *value = v8::RegExp::New(pattern.As<v8::String>(), static_cast<v8::RegEx
p::Flags>(flags)); | |
2142 return true; | |
2143 } | |
2144 | |
2145 bool readBlob(v8::Handle<v8::Value>* value, bool isIndexed) | |
2146 { | |
2147 if (m_version < 3) | |
2148 return false; | |
2149 RefPtrWillBeRawPtr<Blob> blob; | |
2150 if (isIndexed) { | |
2151 if (m_version < 6) | |
2152 return false; | |
2153 ASSERT(m_blobInfo); | |
2154 uint32_t index; | |
2155 if (!doReadUint32(&index) || index >= m_blobInfo->size()) | |
2156 return false; | |
2157 const blink::WebBlobInfo& info = (*m_blobInfo)[index]; | |
2158 blob = Blob::create(getOrCreateBlobDataHandle(info.uuid(), info.type
(), info.size())); | |
2159 } else { | |
2160 ASSERT(!m_blobInfo); | |
2161 String uuid; | |
2162 String type; | |
2163 uint64_t size; | |
2164 ASSERT(!m_blobInfo); | |
2165 if (!readWebCoreString(&uuid)) | |
2166 return false; | |
2167 if (!readWebCoreString(&type)) | |
2168 return false; | |
2169 if (!doReadUint64(&size)) | |
2170 return false; | |
2171 blob = Blob::create(getOrCreateBlobDataHandle(uuid, type, size)); | |
2172 } | |
2173 *value = toV8(blob.release(), m_scriptState->context()->Global(), isolat
e()); | |
2174 return true; | |
2175 } | |
2176 | |
2177 bool readDOMFileSystem(v8::Handle<v8::Value>* value) | |
2178 { | |
2179 uint32_t type; | |
2180 String name; | |
2181 String url; | |
2182 if (!doReadUint32(&type)) | |
2183 return false; | |
2184 if (!readWebCoreString(&name)) | |
2185 return false; | |
2186 if (!readWebCoreString(&url)) | |
2187 return false; | |
2188 DOMFileSystem* fs = DOMFileSystem::create(m_scriptState->executionContex
t(), name, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, url
)); | |
2189 *value = toV8(fs, m_scriptState->context()->Global(), isolate()); | |
2190 return true; | |
2191 } | |
2192 | |
2193 bool readFile(v8::Handle<v8::Value>* value, bool isIndexed) | |
2194 { | |
2195 RefPtrWillBeRawPtr<File> file; | |
2196 if (isIndexed) { | |
2197 if (m_version < 6) | |
2198 return false; | |
2199 file = readFileIndexHelper(); | |
2200 } else { | |
2201 file = readFileHelper(); | |
2202 } | |
2203 if (!file) | |
2204 return false; | |
2205 *value = toV8(file.release(), m_scriptState->context()->Global(), isolat
e()); | |
2206 return true; | |
2207 } | |
2208 | |
2209 bool readFileList(v8::Handle<v8::Value>* value, bool isIndexed) | |
2210 { | |
2211 if (m_version < 3) | |
2212 return false; | |
2213 uint32_t length; | |
2214 if (!doReadUint32(&length)) | |
2215 return false; | |
2216 RefPtrWillBeRawPtr<FileList> fileList = FileList::create(); | |
2217 for (unsigned i = 0; i < length; ++i) { | |
2218 RefPtrWillBeRawPtr<File> file; | |
2219 if (isIndexed) { | |
2220 if (m_version < 6) | |
2221 return false; | |
2222 file = readFileIndexHelper(); | |
2223 } else { | |
2224 file = readFileHelper(); | |
2225 } | |
2226 if (!file) | |
2227 return false; | |
2228 fileList->append(file.release()); | |
2229 } | |
2230 *value = toV8(fileList.release(), m_scriptState->context()->Global(), is
olate()); | |
2231 return true; | |
2232 } | |
2233 | |
2234 bool readCryptoKey(v8::Handle<v8::Value>* value) | |
2235 { | |
2236 uint32_t rawKeyType; | |
2237 if (!doReadUint32(&rawKeyType)) | |
2238 return false; | |
2239 | |
2240 blink::WebCryptoKeyAlgorithm algorithm; | |
2241 blink::WebCryptoKeyType type = blink::WebCryptoKeyTypeSecret; | |
2242 | |
2243 switch (static_cast<CryptoKeySubTag>(rawKeyType)) { | |
2244 case AesKeyTag: | |
2245 if (!doReadAesKey(algorithm, type)) | |
2246 return false; | |
2247 break; | |
2248 case HmacKeyTag: | |
2249 if (!doReadHmacKey(algorithm, type)) | |
2250 return false; | |
2251 break; | |
2252 case RsaHashedKeyTag: | |
2253 if (!doReadRsaHashedKey(algorithm, type)) | |
2254 return false; | |
2255 break; | |
2256 default: | |
2257 return false; | |
2258 } | |
2259 | |
2260 blink::WebCryptoKeyUsageMask usages; | |
2261 bool extractable; | |
2262 if (!doReadKeyUsages(usages, extractable)) | |
2263 return false; | |
2264 | |
2265 uint32_t keyDataLength; | |
2266 if (!doReadUint32(&keyDataLength)) | |
2267 return false; | |
2268 | |
2269 if (m_position + keyDataLength > m_length) | |
2270 return false; | |
2271 | |
2272 const uint8_t* keyData = m_buffer + m_position; | |
2273 m_position += keyDataLength; | |
2274 | |
2275 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | |
2276 if (!blink::Platform::current()->crypto()->deserializeKeyForClone( | |
2277 algorithm, type, extractable, usages, keyData, keyDataLength, key))
{ | |
2278 return false; | |
2279 } | |
2280 | |
2281 *value = toV8(CryptoKey::create(key), m_scriptState->context()->Global()
, isolate()); | |
2282 return true; | |
2283 } | |
2284 | |
2285 PassRefPtrWillBeRawPtr<File> readFileHelper() | |
2286 { | |
2287 if (m_version < 3) | |
2288 return nullptr; | |
2289 ASSERT(!m_blobInfo); | |
2290 String path; | |
2291 String name; | |
2292 String relativePath; | |
2293 String uuid; | |
2294 String type; | |
2295 uint32_t hasSnapshot = 0; | |
2296 uint64_t size = 0; | |
2297 double lastModified = 0; | |
2298 if (!readWebCoreString(&path)) | |
2299 return nullptr; | |
2300 if (m_version >= 4 && !readWebCoreString(&name)) | |
2301 return nullptr; | |
2302 if (m_version >= 4 && !readWebCoreString(&relativePath)) | |
2303 return nullptr; | |
2304 if (!readWebCoreString(&uuid)) | |
2305 return nullptr; | |
2306 if (!readWebCoreString(&type)) | |
2307 return nullptr; | |
2308 if (m_version >= 4 && !doReadUint32(&hasSnapshot)) | |
2309 return nullptr; | |
2310 if (hasSnapshot) { | |
2311 if (!doReadUint64(&size)) | |
2312 return nullptr; | |
2313 if (!doReadNumber(&lastModified)) | |
2314 return nullptr; | |
2315 } | |
2316 return File::create(path, name, relativePath, hasSnapshot > 0, size, las
tModified, getOrCreateBlobDataHandle(uuid, type)); | |
2317 } | |
2318 | |
2319 PassRefPtrWillBeRawPtr<File> readFileIndexHelper() | |
2320 { | |
2321 if (m_version < 3) | |
2322 return nullptr; | |
2323 ASSERT(m_blobInfo); | |
2324 uint32_t index; | |
2325 if (!doReadUint32(&index) || index >= m_blobInfo->size()) | |
2326 return nullptr; | |
2327 const blink::WebBlobInfo& info = (*m_blobInfo)[index]; | |
2328 return File::create(info.filePath(), info.fileName(), info.size(), info.
lastModified(), getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size())
); | |
2329 } | |
2330 | |
2331 template<class T> | |
2332 bool doReadUintHelper(T* value) | |
2333 { | |
2334 *value = 0; | |
2335 uint8_t currentByte; | |
2336 int shift = 0; | |
2337 do { | |
2338 if (m_position >= m_length) | |
2339 return false; | |
2340 currentByte = m_buffer[m_position++]; | |
2341 *value |= ((currentByte & varIntMask) << shift); | |
2342 shift += varIntShift; | |
2343 } while (currentByte & (1 << varIntShift)); | |
2344 return true; | |
2345 } | |
2346 | |
2347 bool doReadUint32(uint32_t* value) | |
2348 { | |
2349 return doReadUintHelper(value); | |
2350 } | |
2351 | |
2352 bool doReadUint64(uint64_t* value) | |
2353 { | |
2354 return doReadUintHelper(value); | |
2355 } | |
2356 | |
2357 bool doReadNumber(double* number) | |
2358 { | |
2359 if (m_position + sizeof(double) > m_length) | |
2360 return false; | |
2361 uint8_t* numberAsByteArray = reinterpret_cast<uint8_t*>(number); | |
2362 for (unsigned i = 0; i < sizeof(double); ++i) | |
2363 numberAsByteArray[i] = m_buffer[m_position++]; | |
2364 return true; | |
2365 } | |
2366 | |
2367 PassRefPtr<BlobDataHandle> getOrCreateBlobDataHandle(const String& uuid, con
st String& type, long long size = -1) | |
2368 { | |
2369 // The containing ssv may have a BDH for this uuid if this ssv is just b
eing | |
2370 // passed from main to worker thread (for example). We use those values
when creating | |
2371 // the new blob instead of cons'ing up a new BDH. | |
2372 // | |
2373 // FIXME: Maybe we should require that it work that way where the ssv mu
st have a BDH for any | |
2374 // blobs it comes across during deserialization. Would require callers t
o explicitly populate | |
2375 // the collection of BDH's for blobs to work, which would encourage life
times to be considered | |
2376 // when passing ssv's around cross process. At present, we get 'lucky' i
n some cases because | |
2377 // the blob in the src process happens to still exist at the time the de
st process is deserializing. | |
2378 // For example in sharedWorker.postMessage(...). | |
2379 BlobDataHandleMap::const_iterator it = m_blobDataHandles.find(uuid); | |
2380 if (it != m_blobDataHandles.end()) { | |
2381 // make assertions about type and size? | |
2382 return it->value; | |
2383 } | |
2384 return BlobDataHandle::create(uuid, type, size); | |
2385 } | |
2386 | |
2387 bool doReadHmacKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCrypto
KeyType& type) | |
2388 { | |
2389 uint32_t lengthBytes; | |
2390 if (!doReadUint32(&lengthBytes)) | |
2391 return false; | |
2392 blink::WebCryptoAlgorithmId hash; | |
2393 if (!doReadAlgorithmId(hash)) | |
2394 return false; | |
2395 algorithm = blink::WebCryptoKeyAlgorithm::createHmac(hash, lengthBytes *
8); | |
2396 type = blink::WebCryptoKeyTypeSecret; | |
2397 return !algorithm.isNull(); | |
2398 } | |
2399 | |
2400 bool doReadAesKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoK
eyType& type) | |
2401 { | |
2402 blink::WebCryptoAlgorithmId id; | |
2403 if (!doReadAlgorithmId(id)) | |
2404 return false; | |
2405 uint32_t lengthBytes; | |
2406 if (!doReadUint32(&lengthBytes)) | |
2407 return false; | |
2408 algorithm = blink::WebCryptoKeyAlgorithm::createAes(id, lengthBytes * 8)
; | |
2409 type = blink::WebCryptoKeyTypeSecret; | |
2410 return !algorithm.isNull(); | |
2411 } | |
2412 | |
2413 bool doReadRsaHashedKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebC
ryptoKeyType& type) | |
2414 { | |
2415 blink::WebCryptoAlgorithmId id; | |
2416 if (!doReadAlgorithmId(id)) | |
2417 return false; | |
2418 | |
2419 uint32_t rawType; | |
2420 if (!doReadUint32(&rawType)) | |
2421 return false; | |
2422 | |
2423 switch (static_cast<AssymetricCryptoKeyType>(rawType)) { | |
2424 case PublicKeyType: | |
2425 type = blink::WebCryptoKeyTypePublic; | |
2426 break; | |
2427 case PrivateKeyType: | |
2428 type = blink::WebCryptoKeyTypePrivate; | |
2429 break; | |
2430 default: | |
2431 return false; | |
2432 } | |
2433 | |
2434 uint32_t modulusLengthBits; | |
2435 if (!doReadUint32(&modulusLengthBits)) | |
2436 return false; | |
2437 | |
2438 uint32_t publicExponentSize; | |
2439 if (!doReadUint32(&publicExponentSize)) | |
2440 return false; | |
2441 | |
2442 if (m_position + publicExponentSize > m_length) | |
2443 return false; | |
2444 | |
2445 const uint8_t* publicExponent = m_buffer + m_position; | |
2446 m_position += publicExponentSize; | |
2447 | |
2448 blink::WebCryptoAlgorithmId hash; | |
2449 if (!doReadAlgorithmId(hash)) | |
2450 return false; | |
2451 algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(id, modulusLen
gthBits, publicExponent, publicExponentSize, hash); | |
2452 | |
2453 return !algorithm.isNull(); | |
2454 } | |
2455 | |
2456 bool doReadAlgorithmId(blink::WebCryptoAlgorithmId& id) | |
2457 { | |
2458 uint32_t rawId; | |
2459 if (!doReadUint32(&rawId)) | |
2460 return false; | |
2461 | |
2462 switch (static_cast<CryptoKeyAlgorithmTag>(rawId)) { | |
2463 case AesCbcTag: | |
2464 id = blink::WebCryptoAlgorithmIdAesCbc; | |
2465 return true; | |
2466 case HmacTag: | |
2467 id = blink::WebCryptoAlgorithmIdHmac; | |
2468 return true; | |
2469 case RsaSsaPkcs1v1_5Tag: | |
2470 id = blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; | |
2471 return true; | |
2472 case Sha1Tag: | |
2473 id = blink::WebCryptoAlgorithmIdSha1; | |
2474 return true; | |
2475 case Sha256Tag: | |
2476 id = blink::WebCryptoAlgorithmIdSha256; | |
2477 return true; | |
2478 case Sha384Tag: | |
2479 id = blink::WebCryptoAlgorithmIdSha384; | |
2480 return true; | |
2481 case Sha512Tag: | |
2482 id = blink::WebCryptoAlgorithmIdSha512; | |
2483 return true; | |
2484 case AesGcmTag: | |
2485 id = blink::WebCryptoAlgorithmIdAesGcm; | |
2486 return true; | |
2487 case RsaOaepTag: | |
2488 id = blink::WebCryptoAlgorithmIdRsaOaep; | |
2489 return true; | |
2490 case AesCtrTag: | |
2491 id = blink::WebCryptoAlgorithmIdAesCtr; | |
2492 return true; | |
2493 case AesKwTag: | |
2494 id = blink::WebCryptoAlgorithmIdAesKw; | |
2495 return true; | |
2496 } | |
2497 | |
2498 return false; | |
2499 } | |
2500 | |
2501 bool doReadKeyUsages(blink::WebCryptoKeyUsageMask& usages, bool& extractable
) | |
2502 { | |
2503 // Reminder to update this when adding new key usages. | |
2504 COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe); | |
2505 const uint32_t allPossibleUsages = ExtractableUsage | EncryptUsage | Dec
ryptUsage | SignUsage | VerifyUsage | DeriveKeyUsage | WrapKeyUsage | UnwrapKeyU
sage | DeriveBitsUsage; | |
2506 | |
2507 uint32_t rawUsages; | |
2508 if (!doReadUint32(&rawUsages)) | |
2509 return false; | |
2510 | |
2511 // Make sure it doesn't contain an unrecognized usage value. | |
2512 if (rawUsages & ~allPossibleUsages) | |
2513 return false; | |
2514 | |
2515 usages = 0; | |
2516 | |
2517 extractable = rawUsages & ExtractableUsage; | |
2518 | |
2519 if (rawUsages & EncryptUsage) | |
2520 usages |= blink::WebCryptoKeyUsageEncrypt; | |
2521 if (rawUsages & DecryptUsage) | |
2522 usages |= blink::WebCryptoKeyUsageDecrypt; | |
2523 if (rawUsages & SignUsage) | |
2524 usages |= blink::WebCryptoKeyUsageSign; | |
2525 if (rawUsages & VerifyUsage) | |
2526 usages |= blink::WebCryptoKeyUsageVerify; | |
2527 if (rawUsages & DeriveKeyUsage) | |
2528 usages |= blink::WebCryptoKeyUsageDeriveKey; | |
2529 if (rawUsages & WrapKeyUsage) | |
2530 usages |= blink::WebCryptoKeyUsageWrapKey; | |
2531 if (rawUsages & UnwrapKeyUsage) | |
2532 usages |= blink::WebCryptoKeyUsageUnwrapKey; | |
2533 if (rawUsages & DeriveBitsUsage) | |
2534 usages |= blink::WebCryptoKeyUsageDeriveBits; | |
2535 | |
2536 return true; | |
2537 } | |
2538 | |
2539 RefPtr<ScriptState> m_scriptState; | |
2540 const uint8_t* m_buffer; | |
2541 const unsigned m_length; | |
2542 unsigned m_position; | |
2543 uint32_t m_version; | |
2544 const WebBlobInfoArray* m_blobInfo; | |
2545 const BlobDataHandleMap& m_blobDataHandles; | |
2546 }; | |
2547 | |
2548 | |
2549 typedef Vector<WTF::ArrayBufferContents, 1> ArrayBufferContentsArray; | |
2550 | |
2551 class Deserializer FINAL : public CompositeCreator { | |
2552 public: | |
2553 Deserializer(Reader& reader, MessagePortArray* messagePorts, ArrayBufferCont
entsArray* arrayBufferContents) | |
2554 : m_reader(reader) | |
2555 , m_transferredMessagePorts(messagePorts) | |
2556 , m_arrayBufferContents(arrayBufferContents) | |
2557 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0) | |
2558 , m_version(0) | |
2559 { | |
2560 } | |
2561 | |
2562 v8::Handle<v8::Value> deserialize() | |
2563 { | |
2564 v8::Isolate* isolate = m_reader.scriptState()->isolate(); | |
2565 if (!m_reader.readVersion(m_version) || m_version > SerializedScriptValu
e::wireFormatVersion) | |
2566 return v8::Null(isolate); | |
2567 m_reader.setVersion(m_version); | |
2568 v8::EscapableHandleScope scope(isolate); | |
2569 while (!m_reader.isEof()) { | |
2570 if (!doDeserialize()) | |
2571 return v8::Null(isolate); | |
2572 } | |
2573 if (stackDepth() != 1 || m_openCompositeReferenceStack.size()) | |
2574 return v8::Null(isolate); | |
2575 v8::Handle<v8::Value> result = scope.Escape(element(0)); | |
2576 return result; | |
2577 } | |
2578 | |
2579 virtual bool newSparseArray(uint32_t) OVERRIDE | |
2580 { | |
2581 v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isol
ate(), 0); | |
2582 openComposite(array); | |
2583 return true; | |
2584 } | |
2585 | |
2586 virtual bool newDenseArray(uint32_t length) OVERRIDE | |
2587 { | |
2588 v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isol
ate(), length); | |
2589 openComposite(array); | |
2590 return true; | |
2591 } | |
2592 | |
2593 virtual bool consumeTopOfStack(v8::Handle<v8::Value>* object) OVERRIDE | |
2594 { | |
2595 if (stackDepth() < 1) | |
2596 return false; | |
2597 *object = element(stackDepth() - 1); | |
2598 pop(1); | |
2599 return true; | |
2600 } | |
2601 | |
2602 virtual bool newObject() OVERRIDE | |
2603 { | |
2604 v8::Local<v8::Object> object = v8::Object::New(m_reader.scriptState()->i
solate()); | |
2605 if (object.IsEmpty()) | |
2606 return false; | |
2607 openComposite(object); | |
2608 return true; | |
2609 } | |
2610 | |
2611 virtual bool completeObject(uint32_t numProperties, v8::Handle<v8::Value>* v
alue) OVERRIDE | |
2612 { | |
2613 v8::Local<v8::Object> object; | |
2614 if (m_version > 0) { | |
2615 v8::Local<v8::Value> composite; | |
2616 if (!closeComposite(&composite)) | |
2617 return false; | |
2618 object = composite.As<v8::Object>(); | |
2619 } else { | |
2620 object = v8::Object::New(m_reader.scriptState()->isolate()); | |
2621 } | |
2622 if (object.IsEmpty()) | |
2623 return false; | |
2624 return initializeObject(object, numProperties, value); | |
2625 } | |
2626 | |
2627 virtual bool completeSparseArray(uint32_t numProperties, uint32_t length, v8
::Handle<v8::Value>* value) OVERRIDE | |
2628 { | |
2629 v8::Local<v8::Array> array; | |
2630 if (m_version > 0) { | |
2631 v8::Local<v8::Value> composite; | |
2632 if (!closeComposite(&composite)) | |
2633 return false; | |
2634 array = composite.As<v8::Array>(); | |
2635 } else { | |
2636 array = v8::Array::New(m_reader.scriptState()->isolate()); | |
2637 } | |
2638 if (array.IsEmpty()) | |
2639 return false; | |
2640 return initializeObject(array, numProperties, value); | |
2641 } | |
2642 | |
2643 virtual bool completeDenseArray(uint32_t numProperties, uint32_t length, v8:
:Handle<v8::Value>* value) OVERRIDE | |
2644 { | |
2645 v8::Local<v8::Array> array; | |
2646 if (m_version > 0) { | |
2647 v8::Local<v8::Value> composite; | |
2648 if (!closeComposite(&composite)) | |
2649 return false; | |
2650 array = composite.As<v8::Array>(); | |
2651 } | |
2652 if (array.IsEmpty()) | |
2653 return false; | |
2654 if (!initializeObject(array, numProperties, value)) | |
2655 return false; | |
2656 if (length > stackDepth()) | |
2657 return false; | |
2658 for (unsigned i = 0, stackPos = stackDepth() - length; i < length; i++,
stackPos++) { | |
2659 v8::Local<v8::Value> elem = element(stackPos); | |
2660 if (!elem->IsUndefined()) | |
2661 array->Set(i, elem); | |
2662 } | |
2663 pop(length); | |
2664 return true; | |
2665 } | |
2666 | |
2667 virtual void pushObjectReference(const v8::Handle<v8::Value>& object) OVERRI
DE | |
2668 { | |
2669 m_objectPool.append(object); | |
2670 } | |
2671 | |
2672 virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Val
ue>* object) OVERRIDE | |
2673 { | |
2674 if (!m_transferredMessagePorts) | |
2675 return false; | |
2676 if (index >= m_transferredMessagePorts->size()) | |
2677 return false; | |
2678 v8::Handle<v8::Object> creationContext = m_reader.scriptState()->context
()->Global(); | |
2679 *object = toV8(m_transferredMessagePorts->at(index).get(), creationConte
xt, m_reader.scriptState()->isolate()); | |
2680 return true; | |
2681 } | |
2682 | |
2683 virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Val
ue>* object) OVERRIDE | |
2684 { | |
2685 if (!m_arrayBufferContents) | |
2686 return false; | |
2687 if (index >= m_arrayBuffers.size()) | |
2688 return false; | |
2689 v8::Handle<v8::Object> result = m_arrayBuffers.at(index); | |
2690 if (result.IsEmpty()) { | |
2691 RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(m_arrayBufferConten
ts->at(index)); | |
2692 buffer->setDeallocationObserver(V8ArrayBufferDeallocationObserver::i
nstanceTemplate()); | |
2693 v8::Isolate* isolate = m_reader.scriptState()->isolate(); | |
2694 v8::Handle<v8::Object> creationContext = m_reader.scriptState()->con
text()->Global(); | |
2695 isolate->AdjustAmountOfExternalAllocatedMemory(buffer->byteLength())
; | |
2696 result = toV8Object(buffer.get(), creationContext, isolate); | |
2697 m_arrayBuffers[index] = result; | |
2698 } | |
2699 *object = result; | |
2700 return true; | |
2701 } | |
2702 | |
2703 virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<
v8::Value>* object) OVERRIDE | |
2704 { | |
2705 if (reference >= m_objectPool.size()) | |
2706 return false; | |
2707 *object = m_objectPool[reference]; | |
2708 return object; | |
2709 } | |
2710 | |
2711 virtual uint32_t objectReferenceCount() OVERRIDE | |
2712 { | |
2713 return m_objectPool.size(); | |
2714 } | |
2715 | |
2716 private: | |
2717 bool initializeObject(v8::Handle<v8::Object> object, uint32_t numProperties,
v8::Handle<v8::Value>* value) | |
2718 { | |
2719 unsigned length = 2 * numProperties; | |
2720 if (length > stackDepth()) | |
2721 return false; | |
2722 for (unsigned i = stackDepth() - length; i < stackDepth(); i += 2) { | |
2723 v8::Local<v8::Value> propertyName = element(i); | |
2724 v8::Local<v8::Value> propertyValue = element(i + 1); | |
2725 object->Set(propertyName, propertyValue); | |
2726 } | |
2727 pop(length); | |
2728 *value = object; | |
2729 return true; | |
2730 } | |
2731 | |
2732 bool doDeserialize() | |
2733 { | |
2734 v8::Local<v8::Value> value; | |
2735 if (!m_reader.read(&value, *this)) | |
2736 return false; | |
2737 if (!value.IsEmpty()) | |
2738 push(value); | |
2739 return true; | |
2740 } | |
2741 | |
2742 void push(v8::Local<v8::Value> value) { m_stack.append(value); } | |
2743 | |
2744 void pop(unsigned length) | |
2745 { | |
2746 ASSERT(length <= m_stack.size()); | |
2747 m_stack.shrink(m_stack.size() - length); | |
2748 } | |
2749 | |
2750 unsigned stackDepth() const { return m_stack.size(); } | |
2751 | |
2752 v8::Local<v8::Value> element(unsigned index) | |
2753 { | |
2754 ASSERT_WITH_SECURITY_IMPLICATION(index < m_stack.size()); | |
2755 return m_stack[index]; | |
2756 } | |
2757 | |
2758 void openComposite(const v8::Local<v8::Value>& object) | |
2759 { | |
2760 uint32_t newObjectReference = m_objectPool.size(); | |
2761 m_openCompositeReferenceStack.append(newObjectReference); | |
2762 m_objectPool.append(object); | |
2763 } | |
2764 | |
2765 bool closeComposite(v8::Handle<v8::Value>* object) | |
2766 { | |
2767 if (!m_openCompositeReferenceStack.size()) | |
2768 return false; | |
2769 uint32_t objectReference = m_openCompositeReferenceStack[m_openComposite
ReferenceStack.size() - 1]; | |
2770 m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size(
) - 1); | |
2771 if (objectReference >= m_objectPool.size()) | |
2772 return false; | |
2773 *object = m_objectPool[objectReference]; | |
2774 return true; | |
2775 } | |
2776 | |
2777 Reader& m_reader; | |
2778 Vector<v8::Local<v8::Value> > m_stack; | |
2779 Vector<v8::Handle<v8::Value> > m_objectPool; | |
2780 Vector<uint32_t> m_openCompositeReferenceStack; | |
2781 MessagePortArray* m_transferredMessagePorts; | |
2782 ArrayBufferContentsArray* m_arrayBufferContents; | |
2783 Vector<v8::Handle<v8::Object> > m_arrayBuffers; | |
2784 uint32_t m_version; | |
2785 }; | |
2786 | |
2787 } // namespace | |
2788 | |
2789 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::V
alue> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, Exc
eptionState& exceptionState, v8::Isolate* isolate) | |
2790 { | |
2791 return adoptRef(new SerializedScriptValue(value, messagePorts, arrayBuffers,
0, exceptionState, isolate)); | |
2792 } | |
2793 | |
2794 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createAndSwallowExcepti
ons(v8::Handle<v8::Value> value, v8::Isolate* isolate) | |
2795 { | |
2796 TrackExceptionState exceptionState; | |
2797 return adoptRef(new SerializedScriptValue(value, 0, 0, 0, exceptionState, is
olate)); | |
2798 } | |
2799 | |
2800 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const ScriptValu
e& value, WebBlobInfoArray* blobInfo, ExceptionState& exceptionState, v8::Isolat
e* isolate) | |
2801 { | |
2802 ASSERT(isolate->InContext()); | |
2803 return adoptRef(new SerializedScriptValue(value.v8Value(), 0, 0, blobInfo, e
xceptionState, isolate)); | |
2804 } | |
2805 | |
2806 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWire(const St
ring& data) | |
2807 { | |
2808 return adoptRef(new SerializedScriptValue(data)); | |
2809 } | |
2810 | |
2811 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWireBytes(con
st Vector<uint8_t>& data) | |
2812 { | |
2813 // Decode wire data from big endian to host byte order. | |
2814 ASSERT(!(data.size() % sizeof(UChar))); | |
2815 size_t length = data.size() / sizeof(UChar); | |
2816 StringBuffer<UChar> buffer(length); | |
2817 const UChar* src = reinterpret_cast<const UChar*>(data.data()); | |
2818 UChar* dst = buffer.characters(); | |
2819 for (size_t i = 0; i < length; i++) | |
2820 dst[i] = ntohs(src[i]); | |
2821 | |
2822 return createFromWire(String::adopt(buffer)); | |
2823 } | |
2824 | |
2825 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& da
ta) | |
2826 { | |
2827 return create(data, v8::Isolate::GetCurrent()); | |
2828 } | |
2829 | |
2830 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& da
ta, v8::Isolate* isolate) | |
2831 { | |
2832 Writer writer; | |
2833 writer.writeWebCoreString(data); | |
2834 String wireData = writer.takeWireString(); | |
2835 return adoptRef(new SerializedScriptValue(wireData)); | |
2836 } | |
2837 | |
2838 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create() | |
2839 { | |
2840 return adoptRef(new SerializedScriptValue()); | |
2841 } | |
2842 | |
2843 PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue() | |
2844 { | |
2845 Writer writer; | |
2846 writer.writeNull(); | |
2847 String wireData = writer.takeWireString(); | |
2848 return adoptRef(new SerializedScriptValue(wireData)); | |
2849 } | |
2850 | |
2851 // Convert serialized string to big endian wire data. | |
2852 void SerializedScriptValue::toWireBytes(Vector<char>& result) const | |
2853 { | |
2854 ASSERT(result.isEmpty()); | |
2855 size_t length = m_data.length(); | |
2856 result.resize(length * sizeof(UChar)); | |
2857 UChar* dst = reinterpret_cast<UChar*>(result.data()); | |
2858 | |
2859 if (m_data.is8Bit()) { | |
2860 const LChar* src = m_data.characters8(); | |
2861 for (size_t i = 0; i < length; i++) | |
2862 dst[i] = htons(static_cast<UChar>(src[i])); | |
2863 } else { | |
2864 const UChar* src = m_data.characters16(); | |
2865 for (size_t i = 0; i < length; i++) | |
2866 dst[i] = htons(src[i]); | |
2867 } | |
2868 } | |
2869 | |
2870 SerializedScriptValue::SerializedScriptValue() | |
2871 : m_externallyAllocatedMemory(0) | |
2872 { | |
2873 } | |
2874 | |
2875 static void neuterArrayBufferInAllWorlds(ArrayBuffer* object) | |
2876 { | |
2877 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | |
2878 if (isMainThread()) { | |
2879 Vector<RefPtr<DOMWrapperWorld> > worlds; | |
2880 DOMWrapperWorld::allWorldsInMainThread(worlds); | |
2881 for (size_t i = 0; i < worlds.size(); i++) { | |
2882 v8::Handle<v8::Object> wrapper = worlds[i]->domDataStore().get<V8Arr
ayBuffer>(object, isolate); | |
2883 if (!wrapper.IsEmpty()) { | |
2884 ASSERT(wrapper->IsArrayBuffer()); | |
2885 v8::Handle<v8::ArrayBuffer>::Cast(wrapper)->Neuter(); | |
2886 } | |
2887 } | |
2888 } else { | |
2889 v8::Handle<v8::Object> wrapper = DOMWrapperWorld::current(isolate).domDa
taStore().get<V8ArrayBuffer>(object, isolate); | |
2890 if (!wrapper.IsEmpty()) { | |
2891 ASSERT(wrapper->IsArrayBuffer()); | |
2892 v8::Handle<v8::ArrayBuffer>::Cast(wrapper)->Neuter(); | |
2893 } | |
2894 } | |
2895 } | |
2896 | |
2897 PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValu
e::transferArrayBuffers(ArrayBufferArray& arrayBuffers, ExceptionState& exceptio
nState, v8::Isolate* isolate) | |
2898 { | |
2899 ASSERT(arrayBuffers.size()); | |
2900 | |
2901 for (size_t i = 0; i < arrayBuffers.size(); i++) { | |
2902 if (arrayBuffers[i]->isNeutered()) { | |
2903 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at ind
ex " + String::number(i) + " is already neutered."); | |
2904 return nullptr; | |
2905 } | |
2906 } | |
2907 | |
2908 OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContents
Array(arrayBuffers.size())); | |
2909 | |
2910 HashSet<ArrayBuffer*> visited; | |
2911 for (size_t i = 0; i < arrayBuffers.size(); i++) { | |
2912 if (visited.contains(arrayBuffers[i].get())) | |
2913 continue; | |
2914 visited.add(arrayBuffers[i].get()); | |
2915 | |
2916 bool result = arrayBuffers[i]->transfer(contents->at(i)); | |
2917 if (!result) { | |
2918 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at ind
ex " + String::number(i) + " could not be transferred."); | |
2919 return nullptr; | |
2920 } | |
2921 | |
2922 neuterArrayBufferInAllWorlds(arrayBuffers[i].get()); | |
2923 } | |
2924 return contents.release(); | |
2925 } | |
2926 | |
2927 SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, Messag
ePortArray* messagePorts, ArrayBufferArray* arrayBuffers, WebBlobInfoArray* blob
Info, ExceptionState& exceptionState, v8::Isolate* isolate) | |
2928 : m_externallyAllocatedMemory(0) | |
2929 { | |
2930 Writer writer; | |
2931 Serializer::Status status; | |
2932 String errorMessage; | |
2933 { | |
2934 v8::TryCatch tryCatch; | |
2935 Serializer serializer(writer, messagePorts, arrayBuffers, blobInfo, m_bl
obDataHandles, tryCatch, ScriptState::current(isolate)); | |
2936 status = serializer.serialize(value); | |
2937 if (status == Serializer::JSException) { | |
2938 // If there was a JS exception thrown, re-throw it. | |
2939 exceptionState.rethrowV8Exception(tryCatch.Exception()); | |
2940 return; | |
2941 } | |
2942 errorMessage = serializer.errorMessage(); | |
2943 } | |
2944 switch (status) { | |
2945 case Serializer::InputError: | |
2946 case Serializer::DataCloneError: | |
2947 exceptionState.throwDOMException(DataCloneError, errorMessage); | |
2948 return; | |
2949 case Serializer::Success: | |
2950 m_data = writer.takeWireString(); | |
2951 ASSERT(m_data.impl()->hasOneRef()); | |
2952 if (arrayBuffers && arrayBuffers->size()) | |
2953 m_arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, exc
eptionState, isolate); | |
2954 return; | |
2955 case Serializer::JSException: | |
2956 ASSERT_NOT_REACHED(); | |
2957 break; | |
2958 } | |
2959 ASSERT_NOT_REACHED(); | |
2960 } | |
2961 | |
2962 SerializedScriptValue::SerializedScriptValue(const String& wireData) | |
2963 : m_externallyAllocatedMemory(0) | |
2964 { | |
2965 m_data = wireData.isolatedCopy(); | |
2966 } | |
2967 | |
2968 v8::Handle<v8::Value> SerializedScriptValue::deserialize(MessagePortArray* messa
gePorts) | |
2969 { | |
2970 return deserialize(v8::Isolate::GetCurrent(), messagePorts, 0); | |
2971 } | |
2972 | |
2973 v8::Handle<v8::Value> SerializedScriptValue::deserialize(v8::Isolate* isolate, M
essagePortArray* messagePorts, const WebBlobInfoArray* blobInfo) | |
2974 { | |
2975 if (!m_data.impl()) | |
2976 return v8::Null(isolate); | |
2977 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes); | |
2978 m_data.ensure16Bit(); | |
2979 // FIXME: SerializedScriptValue shouldn't use String for its underlying | |
2980 // storage. Instead, it should use SharedBuffer or Vector<uint8_t>. The | |
2981 // information stored in m_data isn't even encoded in UTF-16. Instead, | |
2982 // unicode characters are encoded as UTF-8 with two code units per UChar. | |
2983 Reader reader(reinterpret_cast<const uint8_t*>(m_data.impl()->characters16()
), 2 * m_data.length(), blobInfo, m_blobDataHandles, ScriptState::current(isolat
e)); | |
2984 Deserializer deserializer(reader, messagePorts, m_arrayBufferContentsArray.g
et()); | |
2985 | |
2986 // deserialize() can run arbitrary script (e.g., setters), which could resul
t in |this| being destroyed. | |
2987 // Holding a RefPtr ensures we are alive (along with our internal data) thro
ughout the operation. | |
2988 RefPtr<SerializedScriptValue> protect(this); | |
2989 return deserializer.deserialize(); | |
2990 } | |
2991 | |
2992 bool SerializedScriptValue::extractTransferables(v8::Local<v8::Value> value, int
argumentIndex, MessagePortArray& ports, ArrayBufferArray& arrayBuffers, Excepti
onState& exceptionState, v8::Isolate* isolate) | |
2993 { | |
2994 if (isUndefinedOrNull(value)) { | |
2995 ports.resize(0); | |
2996 arrayBuffers.resize(0); | |
2997 return true; | |
2998 } | |
2999 | |
3000 uint32_t length = 0; | |
3001 if (value->IsArray()) { | |
3002 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value); | |
3003 length = array->Length(); | |
3004 } else if (toV8Sequence(value, length, isolate).IsEmpty()) { | |
3005 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentO
rValue(argumentIndex + 1)); | |
3006 return false; | |
3007 } | |
3008 | |
3009 v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value); | |
3010 | |
3011 // Validate the passed array of transferrables. | |
3012 for (unsigned i = 0; i < length; ++i) { | |
3013 v8::Local<v8::Value> transferrable = transferrables->Get(i); | |
3014 // Validation of non-null objects, per HTML5 spec 10.3.3. | |
3015 if (isUndefinedOrNull(transferrable)) { | |
3016 exceptionState.throwDOMException(DataCloneError, "Value at index " +
String::number(i) + " is an untransferable " + (transferrable->IsUndefined() ?
"'undefined'" : "'null'") + " value."); | |
3017 return false; | |
3018 } | |
3019 // Validation of Objects implementing an interface, per WebIDL spec 4.1.
15. | |
3020 if (V8MessagePort::hasInstance(transferrable, isolate)) { | |
3021 RefPtrWillBeRawPtr<MessagePort> port = V8MessagePort::toNative(v8::H
andle<v8::Object>::Cast(transferrable)); | |
3022 // Check for duplicate MessagePorts. | |
3023 if (ports.contains(port)) { | |
3024 exceptionState.throwDOMException(DataCloneError, "Message port a
t index " + String::number(i) + " is a duplicate of an earlier port."); | |
3025 return false; | |
3026 } | |
3027 ports.append(port.release()); | |
3028 } else if (V8ArrayBuffer::hasInstance(transferrable, isolate)) { | |
3029 RefPtr<ArrayBuffer> arrayBuffer = V8ArrayBuffer::toNative(v8::Handle
<v8::Object>::Cast(transferrable)); | |
3030 if (arrayBuffers.contains(arrayBuffer)) { | |
3031 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at
index " + String::number(i) + " is a duplicate of an earlier ArrayBuffer."); | |
3032 return false; | |
3033 } | |
3034 arrayBuffers.append(arrayBuffer.release()); | |
3035 } else { | |
3036 exceptionState.throwDOMException(DataCloneError, "Value at index " +
String::number(i) + " does not have a transferable type."); | |
3037 return false; | |
3038 } | |
3039 } | |
3040 return true; | |
3041 } | |
3042 | |
3043 void SerializedScriptValue::registerMemoryAllocatedWithCurrentScriptContext() | |
3044 { | |
3045 if (m_externallyAllocatedMemory) | |
3046 return; | |
3047 m_externallyAllocatedMemory = static_cast<intptr_t>(m_data.length()); | |
3048 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(m_externall
yAllocatedMemory); | |
3049 } | |
3050 | |
3051 SerializedScriptValue::~SerializedScriptValue() | |
3052 { | |
3053 // If the allocated memory was not registered before, then this class is lik
ely | |
3054 // used in a context other then Worker's onmessage environment and the prese
nce of | |
3055 // current v8 context is not guaranteed. Avoid calling v8 then. | |
3056 if (m_externallyAllocatedMemory) { | |
3057 ASSERT(v8::Isolate::GetCurrent()); | |
3058 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-m_exte
rnallyAllocatedMemory); | |
3059 } | |
3060 } | |
3061 | |
3062 } // namespace WebCore | |
OLD | NEW |