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 52namespace WebCore { 53 54v8::Handle<v8::Value> deserializeIDBValueBuffer(SharedBuffer*, v8::Isolate*); 55 56static 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 73v8::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 107v8::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 154static const size_t maximumDepth = 2000; 155 156static 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 190static 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 199template<typename T> 200static 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 209template<typename T> 210static 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 216static 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 226static bool canSet(v8::Handle<v8::Value>& object, const String& keyPathElement) 227{ 228 return object->IsObject(); 229} 230 231static 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 236static 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 249static 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 267static 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 286static 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 302PassRefPtr<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 325v8::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 338bool 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 363bool 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 379ScriptValue 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 389ScriptValue 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 399PassRefPtr<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 408PassRefPtr<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 419void 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