• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "bindings/v8/IDBBindingUtilities.h"
28 
29 #include "V8DOMStringList.h"
30 #include "V8IDBCursor.h"
31 #include "V8IDBCursorWithValue.h"
32 #include "V8IDBDatabase.h"
33 #include "V8IDBIndex.h"
34 #include "V8IDBKeyRange.h"
35 #include "V8IDBObjectStore.h"
36 #include "V8IDBTransaction.h"
37 #include "bindings/v8/DOMRequestState.h"
38 #include "bindings/v8/SerializedScriptValue.h"
39 #include "bindings/v8/V8Binding.h"
40 #include "bindings/v8/custom/V8ArrayBufferViewCustom.h"
41 #include "bindings/v8/custom/V8Uint8ArrayCustom.h"
42 #include "modules/indexeddb/IDBKey.h"
43 #include "modules/indexeddb/IDBKeyPath.h"
44 #include "modules/indexeddb/IDBKeyRange.h"
45 #include "modules/indexeddb/IDBTracing.h"
46 #include "platform/SharedBuffer.h"
47 #include "wtf/ArrayBufferView.h"
48 #include "wtf/MathExtras.h"
49 #include "wtf/Uint8Array.h"
50 #include "wtf/Vector.h"
51 
52 namespace WebCore {
53 
54 v8::Handle<v8::Value> deserializeIDBValueBuffer(SharedBuffer*, v8::Isolate*);
55 
toV8(const IDBKeyPath & value,v8::Handle<v8::Object> creationContext,v8::Isolate * isolate)56 static v8::Handle<v8::Value> toV8(const IDBKeyPath& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
57 {
58     switch (value.type()) {
59     case IDBKeyPath::NullType:
60         return v8::Null(isolate);
61     case IDBKeyPath::StringType:
62         return v8String(isolate, value.string());
63     case IDBKeyPath::ArrayType:
64         RefPtr<DOMStringList> keyPaths = DOMStringList::create();
65         for (Vector<String>::const_iterator it = value.array().begin(); it != value.array().end(); ++it)
66             keyPaths->append(*it);
67         return toV8(keyPaths.release(), creationContext, isolate);
68     }
69     ASSERT_NOT_REACHED();
70     return v8::Undefined(isolate);
71 }
72 
toV8(const IDBKey * key,v8::Handle<v8::Object> creationContext,v8::Isolate * isolate)73 v8::Handle<v8::Value> toV8(const IDBKey* key, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
74 {
75     if (!key) {
76         // This should be undefined, not null.
77         // Spec: http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBKeyRange
78         return v8Undefined();
79     }
80 
81     switch (key->type()) {
82     case IDBKey::InvalidType:
83     case IDBKey::MinType:
84         ASSERT_NOT_REACHED();
85         return v8Undefined();
86     case IDBKey::NumberType:
87         return v8::Number::New(isolate, key->number());
88     case IDBKey::StringType:
89         return v8String(isolate, key->string());
90     case IDBKey::BinaryType:
91         return toV8(Uint8Array::create(reinterpret_cast<const unsigned char*>(key->binary()->data()), key->binary()->size()), creationContext, isolate);
92     case IDBKey::DateType:
93         return v8::Date::New(isolate, key->date());
94     case IDBKey::ArrayType:
95         {
96             v8::Local<v8::Array> array = v8::Array::New(isolate, key->array().size());
97             for (size_t i = 0; i < key->array().size(); ++i)
98                 array->Set(i, toV8(key->array()[i].get(), creationContext, isolate));
99             return array;
100         }
101     }
102 
103     ASSERT_NOT_REACHED();
104     return v8Undefined();
105 }
106 
toV8(const IDBAny * impl,v8::Handle<v8::Object> creationContext,v8::Isolate * isolate)107 v8::Handle<v8::Value> toV8(const IDBAny* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
108 {
109     if (!impl)
110         return v8::Null(isolate);
111 
112     switch (impl->type()) {
113     case IDBAny::UndefinedType:
114         return v8::Undefined(isolate);
115     case IDBAny::NullType:
116         return v8::Null(isolate);
117     case IDBAny::DOMStringListType:
118         return toV8(impl->domStringList(), creationContext, isolate);
119     case IDBAny::IDBCursorType:
120         return toV8(impl->idbCursor(), creationContext, isolate);
121     case IDBAny::IDBCursorWithValueType:
122         return toV8(impl->idbCursorWithValue(), creationContext, isolate);
123     case IDBAny::IDBDatabaseType:
124         return toV8(impl->idbDatabase(), creationContext, isolate);
125     case IDBAny::IDBIndexType:
126         return toV8(impl->idbIndex(), creationContext, isolate);
127     case IDBAny::IDBObjectStoreType:
128         return toV8(impl->idbObjectStore(), creationContext, isolate);
129     case IDBAny::IDBTransactionType:
130         return toV8(impl->idbTransaction(), creationContext, isolate);
131     case IDBAny::BufferType:
132         return deserializeIDBValueBuffer(impl->buffer(), isolate);
133     case IDBAny::StringType:
134         return v8String(isolate, impl->string());
135     case IDBAny::IntegerType:
136         return v8::Number::New(isolate, impl->integer());
137     case IDBAny::KeyType:
138         return toV8(impl->key(), creationContext, isolate);
139     case IDBAny::KeyPathType:
140         return toV8(impl->keyPath(), creationContext, isolate);
141     case IDBAny::BufferKeyAndKeyPathType: {
142         v8::Handle<v8::Value> value = deserializeIDBValueBuffer(impl->buffer(), isolate);
143         v8::Handle<v8::Value> key = toV8(impl->key(), creationContext, isolate);
144         bool injected = injectV8KeyIntoV8Value(key, value, impl->keyPath(), isolate);
145         ASSERT_UNUSED(injected, injected);
146         return value;
147     }
148     }
149 
150     ASSERT_NOT_REACHED();
151     return v8::Undefined(isolate);
152 }
153 
154 static const size_t maximumDepth = 2000;
155 
createIDBKeyFromValue(v8::Handle<v8::Value> value,Vector<v8::Handle<v8::Array>> & stack,v8::Isolate * isolate)156 static PassRefPtr<IDBKey> createIDBKeyFromValue(v8::Handle<v8::Value> value, Vector<v8::Handle<v8::Array> >& stack, v8::Isolate* isolate)
157 {
158     if (value->IsNumber() && !std::isnan(value->NumberValue()))
159         return IDBKey::createNumber(value->NumberValue());
160     if (value->IsString())
161         return IDBKey::createString(toCoreString(value.As<v8::String>()));
162     if (value->IsDate() && !std::isnan(value->NumberValue()))
163         return IDBKey::createDate(value->NumberValue());
164     if (value->IsArray()) {
165         v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
166 
167         if (stack.contains(array))
168             return 0;
169         if (stack.size() >= maximumDepth)
170             return 0;
171         stack.append(array);
172 
173         IDBKey::KeyArray subkeys;
174         uint32_t length = array->Length();
175         for (uint32_t i = 0; i < length; ++i) {
176             v8::Local<v8::Value> item = array->Get(v8::Int32::New(i, isolate));
177             RefPtr<IDBKey> subkey = createIDBKeyFromValue(item, stack, isolate);
178             if (!subkey)
179                 subkeys.append(IDBKey::createInvalid());
180             else
181                 subkeys.append(subkey);
182         }
183 
184         stack.removeLast();
185         return IDBKey::createArray(subkeys);
186     }
187     return 0;
188 }
189 
createIDBKeyFromValue(v8::Handle<v8::Value> value,v8::Isolate * isolate)190 static PassRefPtr<IDBKey> createIDBKeyFromValue(v8::Handle<v8::Value> value, v8::Isolate* isolate)
191 {
192     Vector<v8::Handle<v8::Array> > stack;
193     RefPtr<IDBKey> key = createIDBKeyFromValue(value, stack, isolate);
194     if (key)
195         return key;
196     return IDBKey::createInvalid();
197 }
198 
199 template<typename T>
getValueFrom(T indexOrName,v8::Handle<v8::Value> & v8Value)200 static bool getValueFrom(T indexOrName, v8::Handle<v8::Value>& v8Value)
201 {
202     v8::Local<v8::Object> object = v8Value->ToObject();
203     if (!object->Has(indexOrName))
204         return false;
205     v8Value = object->Get(indexOrName);
206     return true;
207 }
208 
209 template<typename T>
setValue(v8::Handle<v8::Value> & v8Object,T indexOrName,const v8::Handle<v8::Value> & v8Value)210 static bool setValue(v8::Handle<v8::Value>& v8Object, T indexOrName, const v8::Handle<v8::Value>& v8Value)
211 {
212     v8::Local<v8::Object> object = v8Object->ToObject();
213     return object->Set(indexOrName, v8Value);
214 }
215 
get(v8::Handle<v8::Value> & object,const String & keyPathElement,v8::Handle<v8::Value> & result,v8::Isolate * isolate)216 static bool get(v8::Handle<v8::Value>& object, const String& keyPathElement, v8::Handle<v8::Value>& result, v8::Isolate* isolate)
217 {
218     if (object->IsString() && keyPathElement == "length") {
219         int32_t length = v8::Handle<v8::String>::Cast(object)->Length();
220         result = v8::Number::New(isolate, length);
221         return true;
222     }
223     return object->IsObject() && getValueFrom(v8String(isolate, keyPathElement), result);
224 }
225 
canSet(v8::Handle<v8::Value> & object,const String & keyPathElement)226 static bool canSet(v8::Handle<v8::Value>& object, const String& keyPathElement)
227 {
228     return object->IsObject();
229 }
230 
set(v8::Handle<v8::Value> & object,const String & keyPathElement,const v8::Handle<v8::Value> & v8Value,v8::Isolate * isolate)231 static bool set(v8::Handle<v8::Value>& object, const String& keyPathElement, const v8::Handle<v8::Value>& v8Value, v8::Isolate* isolate)
232 {
233     return canSet(object, keyPathElement) && setValue(object, v8String(isolate, keyPathElement), v8Value);
234 }
235 
getNthValueOnKeyPath(v8::Handle<v8::Value> & rootValue,const Vector<String> & keyPathElements,size_t index,v8::Isolate * isolate)236 static v8::Handle<v8::Value> getNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index, v8::Isolate* isolate)
237 {
238     v8::Handle<v8::Value> currentValue(rootValue);
239     ASSERT(index <= keyPathElements.size());
240     for (size_t i = 0; i < index; ++i) {
241         v8::Handle<v8::Value> parentValue(currentValue);
242         if (!get(parentValue, keyPathElements[i], currentValue, isolate))
243             return v8Undefined();
244     }
245 
246     return currentValue;
247 }
248 
canInjectNthValueOnKeyPath(v8::Handle<v8::Value> & rootValue,const Vector<String> & keyPathElements,size_t index,v8::Isolate * isolate)249 static bool canInjectNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index, v8::Isolate* isolate)
250 {
251     if (!rootValue->IsObject())
252         return false;
253 
254     v8::Handle<v8::Value> currentValue(rootValue);
255 
256     ASSERT(index <= keyPathElements.size());
257     for (size_t i = 0; i < index; ++i) {
258         v8::Handle<v8::Value> parentValue(currentValue);
259         const String& keyPathElement = keyPathElements[i];
260         if (!get(parentValue, keyPathElement, currentValue, isolate))
261             return canSet(parentValue, keyPathElement);
262     }
263     return true;
264 }
265 
266 
ensureNthValueOnKeyPath(v8::Handle<v8::Value> & rootValue,const Vector<String> & keyPathElements,size_t index,v8::Isolate * isolate)267 static v8::Handle<v8::Value> ensureNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index, v8::Isolate* isolate)
268 {
269     v8::Handle<v8::Value> currentValue(rootValue);
270 
271     ASSERT(index <= keyPathElements.size());
272     for (size_t i = 0; i < index; ++i) {
273         v8::Handle<v8::Value> parentValue(currentValue);
274         const String& keyPathElement = keyPathElements[i];
275         if (!get(parentValue, keyPathElement, currentValue, isolate)) {
276             v8::Handle<v8::Object> object = v8::Object::New();
277             if (!set(parentValue, keyPathElement, object, isolate))
278                 return v8Undefined();
279             currentValue = object;
280         }
281     }
282 
283     return currentValue;
284 }
285 
createIDBKeyFromScriptValueAndKeyPath(const ScriptValue & value,const String & keyPath,v8::Isolate * isolate)286 static PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(const ScriptValue& value, const String& keyPath, v8::Isolate* isolate)
287 {
288     Vector<String> keyPathElements;
289     IDBKeyPathParseError error;
290     IDBParseKeyPath(keyPath, keyPathElements, error);
291     ASSERT(error == IDBKeyPathParseErrorNone);
292     ASSERT(isolate->InContext());
293 
294     v8::HandleScope handleScope(isolate);
295     v8::Handle<v8::Value> v8Value(value.v8Value());
296     v8::Handle<v8::Value> v8Key(getNthValueOnKeyPath(v8Value, keyPathElements, keyPathElements.size(), isolate));
297     if (v8Key.IsEmpty())
298         return 0;
299     return createIDBKeyFromValue(v8Key, isolate);
300 }
301 
createIDBKeyFromScriptValueAndKeyPath(DOMRequestState * state,const ScriptValue & value,const IDBKeyPath & keyPath)302 PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(DOMRequestState* state, const ScriptValue& value, const IDBKeyPath& keyPath)
303 {
304     IDB_TRACE("createIDBKeyFromScriptValueAndKeyPath");
305     ASSERT(!keyPath.isNull());
306     v8::Isolate* isolate = state ? state->context()->GetIsolate() : v8::Isolate::GetCurrent();
307     ASSERT(isolate->InContext());
308     v8::HandleScope handleScope(isolate);
309     if (keyPath.type() == IDBKeyPath::ArrayType) {
310         IDBKey::KeyArray result;
311         const Vector<String>& array = keyPath.array();
312         for (size_t i = 0; i < array.size(); ++i) {
313             RefPtr<IDBKey> key = createIDBKeyFromScriptValueAndKeyPath(value, array[i], isolate);
314             if (!key)
315                 return 0;
316             result.append(key);
317         }
318         return IDBKey::createArray(result);
319     }
320 
321     ASSERT(keyPath.type() == IDBKeyPath::StringType);
322     return createIDBKeyFromScriptValueAndKeyPath(value, keyPath.string(), isolate);
323 }
324 
deserializeIDBValueBuffer(SharedBuffer * buffer,v8::Isolate * isolate)325 v8::Handle<v8::Value> deserializeIDBValueBuffer(SharedBuffer* buffer, v8::Isolate* isolate)
326 {
327     ASSERT(isolate->InContext());
328     if (!buffer)
329         return v8::Null(isolate);
330 
331     // FIXME: The extra copy here can be eliminated by allowing SerializedScriptValue to take a raw const char* or const uint8_t*.
332     Vector<uint8_t> value;
333     value.append(buffer->data(), buffer->size());
334     RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::createFromWireBytes(value);
335     return serializedValue->deserialize(isolate);
336 }
337 
injectV8KeyIntoV8Value(v8::Handle<v8::Value> key,v8::Handle<v8::Value> value,const IDBKeyPath & keyPath,v8::Isolate * isolate)338 bool injectV8KeyIntoV8Value(v8::Handle<v8::Value> key, v8::Handle<v8::Value> value, const IDBKeyPath& keyPath, v8::Isolate* isolate)
339 {
340     IDB_TRACE("injectIDBV8KeyIntoV8Value");
341     ASSERT(isolate->InContext());
342 
343     ASSERT(keyPath.type() == IDBKeyPath::StringType);
344     Vector<String> keyPathElements;
345     IDBKeyPathParseError error;
346     IDBParseKeyPath(keyPath.string(), keyPathElements, error);
347     ASSERT(error == IDBKeyPathParseErrorNone);
348 
349     if (!keyPathElements.size())
350         return false;
351 
352     v8::HandleScope handleScope(isolate);
353     v8::Handle<v8::Value> parent(ensureNthValueOnKeyPath(value, keyPathElements, keyPathElements.size() - 1, isolate));
354     if (parent.IsEmpty())
355         return false;
356 
357     if (!set(parent, keyPathElements.last(), key, isolate))
358         return false;
359 
360     return true;
361 }
362 
canInjectIDBKeyIntoScriptValue(DOMRequestState * state,const ScriptValue & scriptValue,const IDBKeyPath & keyPath)363 bool canInjectIDBKeyIntoScriptValue(DOMRequestState* state, const ScriptValue& scriptValue, const IDBKeyPath& keyPath)
364 {
365     IDB_TRACE("canInjectIDBKeyIntoScriptValue");
366     ASSERT(keyPath.type() == IDBKeyPath::StringType);
367     Vector<String> keyPathElements;
368     IDBKeyPathParseError error;
369     IDBParseKeyPath(keyPath.string(), keyPathElements, error);
370     ASSERT(error == IDBKeyPathParseErrorNone);
371 
372     if (!keyPathElements.size())
373         return false;
374 
375     v8::Handle<v8::Value> v8Value(scriptValue.v8Value());
376     return canInjectNthValueOnKeyPath(v8Value, keyPathElements, keyPathElements.size() - 1, state->context()->GetIsolate());
377 }
378 
idbAnyToScriptValue(DOMRequestState * state,PassRefPtr<IDBAny> any)379 ScriptValue idbAnyToScriptValue(DOMRequestState* state, PassRefPtr<IDBAny> any)
380 {
381     v8::Isolate* isolate = state ? state->context()->GetIsolate() : v8::Isolate::GetCurrent();
382     ASSERT(isolate->InContext());
383     v8::Local<v8::Context> context = state ? state->context() : isolate->GetCurrentContext();
384     v8::HandleScope handleScope(isolate);
385     v8::Handle<v8::Value> v8Value(toV8(any.get(), context->Global(), isolate));
386     return ScriptValue(v8Value, isolate);
387 }
388 
idbKeyToScriptValue(DOMRequestState * state,PassRefPtr<IDBKey> key)389 ScriptValue idbKeyToScriptValue(DOMRequestState* state, PassRefPtr<IDBKey> key)
390 {
391     v8::Isolate* isolate = state ? state->context()->GetIsolate() : v8::Isolate::GetCurrent();
392     ASSERT(isolate->InContext());
393     v8::Local<v8::Context> context = state ? state->context() : isolate->GetCurrentContext();
394     v8::HandleScope handleScope(isolate);
395     v8::Handle<v8::Value> v8Value(toV8(key.get(), context->Global(), isolate));
396     return ScriptValue(v8Value, isolate);
397 }
398 
scriptValueToIDBKey(DOMRequestState * state,const ScriptValue & scriptValue)399 PassRefPtr<IDBKey> scriptValueToIDBKey(DOMRequestState* state, const ScriptValue& scriptValue)
400 {
401     v8::Isolate* isolate = state ? state->context()->GetIsolate() : v8::Isolate::GetCurrent();
402     ASSERT(isolate->InContext());
403     v8::HandleScope handleScope(isolate);
404     v8::Handle<v8::Value> v8Value(scriptValue.v8Value());
405     return createIDBKeyFromValue(v8Value, isolate);
406 }
407 
scriptValueToIDBKeyRange(DOMRequestState * state,const ScriptValue & scriptValue)408 PassRefPtr<IDBKeyRange> scriptValueToIDBKeyRange(DOMRequestState* state, const ScriptValue& scriptValue)
409 {
410     v8::Isolate* isolate = state ? state->context()->GetIsolate() : v8::Isolate::GetCurrent();
411     v8::HandleScope handleScope(isolate);
412     v8::Handle<v8::Value> value(scriptValue.v8Value());
413     if (V8IDBKeyRange::hasInstance(value, isolate, worldType(isolate)))
414         return V8IDBKeyRange::toNative(value.As<v8::Object>());
415     return 0;
416 }
417 
418 #ifndef NDEBUG
assertPrimaryKeyValidOrInjectable(DOMRequestState * state,PassRefPtr<SharedBuffer> buffer,PassRefPtr<IDBKey> prpKey,const IDBKeyPath & keyPath)419 void assertPrimaryKeyValidOrInjectable(DOMRequestState* state, PassRefPtr<SharedBuffer> buffer, PassRefPtr<IDBKey> prpKey, const IDBKeyPath& keyPath)
420 {
421     RefPtr<IDBKey> key(prpKey);
422 
423     DOMRequestState::Scope scope(*state);
424     v8::Isolate* isolate = state ? state->context()->GetIsolate() : v8::Isolate::GetCurrent();
425 
426     ScriptValue keyValue = idbKeyToScriptValue(state, key);
427     ScriptValue scriptValue(deserializeIDBValueBuffer(buffer.get(), isolate), isolate);
428 
429     RefPtr<IDBKey> expectedKey = createIDBKeyFromScriptValueAndKeyPath(state, scriptValue, keyPath);
430     ASSERT(!expectedKey || expectedKey->isEqual(key.get()));
431 
432     bool injected = injectV8KeyIntoV8Value(keyValue.v8Value(), scriptValue.v8Value(), keyPath, isolate);
433     ASSERT_UNUSED(injected, injected);
434 }
435 #endif
436 
437 } // namespace WebCore
438