| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 switch (key->getType()) { | 97 switch (key->getType()) { |
| 98 case IDBKey::InvalidType: | 98 case IDBKey::InvalidType: |
| 99 case IDBKey::TypeEnumMax: | 99 case IDBKey::TypeEnumMax: |
| 100 ASSERT_NOT_REACHED(); | 100 ASSERT_NOT_REACHED(); |
| 101 return v8Undefined(); | 101 return v8Undefined(); |
| 102 case IDBKey::NumberType: | 102 case IDBKey::NumberType: |
| 103 return v8::Number::New(isolate, key->number()); | 103 return v8::Number::New(isolate, key->number()); |
| 104 case IDBKey::StringType: | 104 case IDBKey::StringType: |
| 105 return v8String(isolate, key->string()); | 105 return v8String(isolate, key->string()); |
| 106 case IDBKey::BinaryType: | 106 case IDBKey::BinaryType: |
| 107 // Experimental feature: binary keys | 107 // https://w3c.github.io/IndexedDB/#convert-a-value-to-a-key |
| 108 // https://w3c.github.io/IndexedDB/#steps-to-convert-a-key-to-a-value | |
| 109 return ToV8(DOMArrayBuffer::create(reinterpret_cast<const unsigned char*>( | 108 return ToV8(DOMArrayBuffer::create(reinterpret_cast<const unsigned char*>( |
| 110 key->binary()->data()), | 109 key->binary()->data()), |
| 111 key->binary()->size()), | 110 key->binary()->size()), |
| 112 creationContext, isolate); | 111 creationContext, isolate); |
| 113 case IDBKey::DateType: | 112 case IDBKey::DateType: |
| 114 return v8::Date::New(context, key->date()).ToLocalChecked(); | 113 return v8::Date::New(context, key->date()).ToLocalChecked(); |
| 115 case IDBKey::ArrayType: { | 114 case IDBKey::ArrayType: { |
| 116 v8::Local<v8::Array> array = v8::Array::New(isolate, key->array().size()); | 115 v8::Local<v8::Array> array = v8::Array::New(isolate, key->array().size()); |
| 117 for (size_t i = 0; i < key->array().size(); ++i) { | 116 for (size_t i = 0; i < key->array().size(); ++i) { |
| 118 v8::Local<v8::Value> value = | 117 v8::Local<v8::Value> value = |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 | 169 |
| 171 ASSERT_NOT_REACHED(); | 170 ASSERT_NOT_REACHED(); |
| 172 return v8::Undefined(isolate); | 171 return v8::Undefined(isolate); |
| 173 } | 172 } |
| 174 | 173 |
| 175 static const size_t maximumDepth = 2000; | 174 static const size_t maximumDepth = 2000; |
| 176 | 175 |
| 177 static IDBKey* createIDBKeyFromValue(v8::Isolate* isolate, | 176 static IDBKey* createIDBKeyFromValue(v8::Isolate* isolate, |
| 178 v8::Local<v8::Value> value, | 177 v8::Local<v8::Value> value, |
| 179 Vector<v8::Local<v8::Array>>& stack, | 178 Vector<v8::Local<v8::Array>>& stack, |
| 180 ExceptionState& exceptionState, | 179 ExceptionState& exceptionState) { |
| 181 bool allowExperimentalTypes = false) { | |
| 182 if (value->IsNumber() && !std::isnan(value.As<v8::Number>()->Value())) | 180 if (value->IsNumber() && !std::isnan(value.As<v8::Number>()->Value())) |
| 183 return IDBKey::createNumber(value.As<v8::Number>()->Value()); | 181 return IDBKey::createNumber(value.As<v8::Number>()->Value()); |
| 184 if (value->IsString()) | 182 if (value->IsString()) |
| 185 return IDBKey::createString(toCoreString(value.As<v8::String>())); | 183 return IDBKey::createString(toCoreString(value.As<v8::String>())); |
| 186 if (value->IsDate() && !std::isnan(value.As<v8::Date>()->ValueOf())) | 184 if (value->IsDate() && !std::isnan(value.As<v8::Date>()->ValueOf())) |
| 187 return IDBKey::createDate(value.As<v8::Date>()->ValueOf()); | 185 return IDBKey::createDate(value.As<v8::Date>()->ValueOf()); |
| 188 if (allowExperimentalTypes || | 186 |
| 189 RuntimeEnabledFeatures::indexedDBExperimentalEnabled()) { | 187 // https://w3c.github.io/IndexedDB/#convert-a-key-to-a-value |
| 190 // Experimental feature: binary keys | 188 if (value->IsArrayBuffer()) { |
| 191 // https://w3c.github.io/IndexedDB/#dfn-convert-a-value-to-a-key | 189 DOMArrayBuffer* buffer = V8ArrayBuffer::toImpl(value.As<v8::Object>()); |
| 192 if (value->IsArrayBuffer()) { | 190 if (buffer->isNeutered()) { |
| 193 DOMArrayBuffer* buffer = V8ArrayBuffer::toImpl(value.As<v8::Object>()); | 191 exceptionState.throwTypeError("The ArrayBuffer is neutered."); |
| 194 if (buffer->isNeutered()) { | 192 return nullptr; |
| 195 exceptionState.throwTypeError("The ArrayBuffer is neutered."); | |
| 196 return nullptr; | |
| 197 } | |
| 198 const char* start = static_cast<const char*>(buffer->data()); | |
| 199 size_t length = buffer->byteLength(); | |
| 200 return IDBKey::createBinary(SharedBuffer::create(start, length)); | |
| 201 } | 193 } |
| 202 if (value->IsArrayBufferView()) { | 194 const char* start = static_cast<const char*>(buffer->data()); |
| 203 DOMArrayBufferView* view = | 195 size_t length = buffer->byteLength(); |
| 204 V8ArrayBufferView::toImpl(value.As<v8::Object>()); | 196 return IDBKey::createBinary(SharedBuffer::create(start, length)); |
| 205 if (view->buffer()->isNeutered()) { | 197 } |
| 206 exceptionState.throwTypeError("The viewed ArrayBuffer is neutered."); | 198 if (value->IsArrayBufferView()) { |
| 207 return nullptr; | 199 DOMArrayBufferView* view = |
| 208 } | 200 V8ArrayBufferView::toImpl(value.As<v8::Object>()); |
| 209 const char* start = static_cast<const char*>(view->baseAddress()); | 201 if (view->buffer()->isNeutered()) { |
| 210 size_t length = view->byteLength(); | 202 exceptionState.throwTypeError("The viewed ArrayBuffer is neutered."); |
| 211 return IDBKey::createBinary(SharedBuffer::create(start, length)); | 203 return nullptr; |
| 212 } | 204 } |
| 205 const char* start = static_cast<const char*>(view->baseAddress()); |
| 206 size_t length = view->byteLength(); |
| 207 return IDBKey::createBinary(SharedBuffer::create(start, length)); |
| 213 } | 208 } |
| 209 |
| 214 if (value->IsArray()) { | 210 if (value->IsArray()) { |
| 215 v8::Local<v8::Array> array = value.As<v8::Array>(); | 211 v8::Local<v8::Array> array = value.As<v8::Array>(); |
| 216 | 212 |
| 217 if (stack.contains(array)) | 213 if (stack.contains(array)) |
| 218 return nullptr; | 214 return nullptr; |
| 219 if (stack.size() >= maximumDepth) | 215 if (stack.size() >= maximumDepth) |
| 220 return nullptr; | 216 return nullptr; |
| 221 stack.push_back(array); | 217 stack.push_back(array); |
| 222 | 218 |
| 223 IDBKey::KeyArray subkeys; | 219 IDBKey::KeyArray subkeys; |
| 224 uint32_t length = array->Length(); | 220 uint32_t length = array->Length(); |
| 225 v8::TryCatch block(isolate); | 221 v8::TryCatch block(isolate); |
| 226 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | 222 v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| 227 for (uint32_t i = 0; i < length; ++i) { | 223 for (uint32_t i = 0; i < length; ++i) { |
| 228 if (!v8CallBoolean(array->HasOwnProperty(context, i))) | 224 if (!v8CallBoolean(array->HasOwnProperty(context, i))) |
| 229 return nullptr; | 225 return nullptr; |
| 230 v8::Local<v8::Value> item; | 226 v8::Local<v8::Value> item; |
| 231 if (!v8Call(array->Get(context, i), item, block)) { | 227 if (!v8Call(array->Get(context, i), item, block)) { |
| 232 exceptionState.rethrowV8Exception(block.Exception()); | 228 exceptionState.rethrowV8Exception(block.Exception()); |
| 233 return nullptr; | 229 return nullptr; |
| 234 } | 230 } |
| 235 IDBKey* subkey = createIDBKeyFromValue( | 231 IDBKey* subkey = |
| 236 isolate, item, stack, exceptionState, allowExperimentalTypes); | 232 createIDBKeyFromValue(isolate, item, stack, exceptionState); |
| 237 if (!subkey) | 233 if (!subkey) |
| 238 subkeys.push_back(IDBKey::createInvalid()); | 234 subkeys.push_back(IDBKey::createInvalid()); |
| 239 else | 235 else |
| 240 subkeys.push_back(subkey); | 236 subkeys.push_back(subkey); |
| 241 } | 237 } |
| 242 | 238 |
| 243 stack.pop_back(); | 239 stack.pop_back(); |
| 244 return IDBKey::createArray(subkeys); | 240 return IDBKey::createArray(subkeys); |
| 245 } | 241 } |
| 246 return nullptr; | 242 return nullptr; |
| 247 } | 243 } |
| 248 | 244 |
| 249 static IDBKey* createIDBKeyFromValue(v8::Isolate* isolate, | 245 static IDBKey* createIDBKeyFromValue(v8::Isolate* isolate, |
| 250 v8::Local<v8::Value> value, | 246 v8::Local<v8::Value> value, |
| 251 ExceptionState& exceptionState, | 247 ExceptionState& exceptionState) { |
| 252 bool allowExperimentalTypes = false) { | |
| 253 Vector<v8::Local<v8::Array>> stack; | 248 Vector<v8::Local<v8::Array>> stack; |
| 254 if (IDBKey* key = createIDBKeyFromValue(isolate, value, stack, exceptionState, | 249 if (IDBKey* key = |
| 255 allowExperimentalTypes)) | 250 createIDBKeyFromValue(isolate, value, stack, exceptionState)) |
| 256 return key; | 251 return key; |
| 257 return IDBKey::createInvalid(); | 252 return IDBKey::createInvalid(); |
| 258 } | 253 } |
| 259 | 254 |
| 260 // Indexed DB key paths should apply to explicitly copied properties (that | 255 // Indexed DB key paths should apply to explicitly copied properties (that |
| 261 // will be "own" properties when deserialized) as well as the following. | 256 // will be "own" properties when deserialized) as well as the following. |
| 262 // http://www.w3.org/TR/IndexedDB/#key-path-construct | 257 // http://www.w3.org/TR/IndexedDB/#key-path-construct |
| 263 static bool isImplicitProperty(v8::Isolate* isolate, | 258 static bool isImplicitProperty(v8::Isolate* isolate, |
| 264 v8::Local<v8::Value> value, | 259 v8::Local<v8::Value> value, |
| 265 const String& name) { | 260 const String& name) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 280 Vector<String> elements; | 275 Vector<String> elements; |
| 281 IDBKeyPathParseError error; | 276 IDBKeyPathParseError error; |
| 282 IDBParseKeyPath(keyPath, elements, error); | 277 IDBParseKeyPath(keyPath, elements, error); |
| 283 ASSERT(error == IDBKeyPathParseErrorNone); | 278 ASSERT(error == IDBKeyPathParseErrorNone); |
| 284 return elements; | 279 return elements; |
| 285 } | 280 } |
| 286 | 281 |
| 287 static IDBKey* createIDBKeyFromValueAndKeyPath(v8::Isolate* isolate, | 282 static IDBKey* createIDBKeyFromValueAndKeyPath(v8::Isolate* isolate, |
| 288 v8::Local<v8::Value> v8Value, | 283 v8::Local<v8::Value> v8Value, |
| 289 const String& keyPath, | 284 const String& keyPath, |
| 290 ExceptionState& exceptionState, | 285 ExceptionState& exceptionState) { |
| 291 bool allowExperimentalTypes) { | |
| 292 Vector<String> keyPathElements = parseKeyPath(keyPath); | 286 Vector<String> keyPathElements = parseKeyPath(keyPath); |
| 293 ASSERT(isolate->InContext()); | 287 ASSERT(isolate->InContext()); |
| 294 | 288 |
| 295 v8::HandleScope handleScope(isolate); | 289 v8::HandleScope handleScope(isolate); |
| 296 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | 290 v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| 297 v8::TryCatch block(isolate); | 291 v8::TryCatch block(isolate); |
| 298 for (size_t i = 0; i < keyPathElements.size(); ++i) { | 292 for (size_t i = 0; i < keyPathElements.size(); ++i) { |
| 299 const String& element = keyPathElements[i]; | 293 const String& element = keyPathElements[i]; |
| 300 | 294 |
| 301 // Special cases from https://w3c.github.io/IndexedDB/#key-path-construct | 295 // Special cases from https://w3c.github.io/IndexedDB/#key-path-construct |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 } | 343 } |
| 350 | 344 |
| 351 v8::Local<v8::String> key = v8String(isolate, element); | 345 v8::Local<v8::String> key = v8String(isolate, element); |
| 352 if (!v8CallBoolean(object->HasOwnProperty(context, key))) | 346 if (!v8CallBoolean(object->HasOwnProperty(context, key))) |
| 353 return nullptr; | 347 return nullptr; |
| 354 if (!v8Call(object->Get(context, key), v8Value, block)) { | 348 if (!v8Call(object->Get(context, key), v8Value, block)) { |
| 355 exceptionState.rethrowV8Exception(block.Exception()); | 349 exceptionState.rethrowV8Exception(block.Exception()); |
| 356 return nullptr; | 350 return nullptr; |
| 357 } | 351 } |
| 358 } | 352 } |
| 359 return createIDBKeyFromValue(isolate, v8Value, exceptionState, | 353 return createIDBKeyFromValue(isolate, v8Value, exceptionState); |
| 360 allowExperimentalTypes); | |
| 361 } | 354 } |
| 362 | 355 |
| 363 static IDBKey* createIDBKeyFromValueAndKeyPath( | 356 static IDBKey* createIDBKeyFromValueAndKeyPath(v8::Isolate* isolate, |
| 364 v8::Isolate* isolate, | 357 v8::Local<v8::Value> value, |
| 365 v8::Local<v8::Value> value, | 358 const IDBKeyPath& keyPath, |
| 366 const IDBKeyPath& keyPath, | 359 ExceptionState& exceptionState) { |
| 367 ExceptionState& exceptionState, | |
| 368 bool allowExperimentalTypes = false) { | |
| 369 ASSERT(!keyPath.isNull()); | 360 ASSERT(!keyPath.isNull()); |
| 370 v8::HandleScope handleScope(isolate); | 361 v8::HandleScope handleScope(isolate); |
| 371 if (keyPath.getType() == IDBKeyPath::ArrayType) { | 362 if (keyPath.getType() == IDBKeyPath::ArrayType) { |
| 372 IDBKey::KeyArray result; | 363 IDBKey::KeyArray result; |
| 373 const Vector<String>& array = keyPath.array(); | 364 const Vector<String>& array = keyPath.array(); |
| 374 for (size_t i = 0; i < array.size(); ++i) { | 365 for (size_t i = 0; i < array.size(); ++i) { |
| 375 IDBKey* key = createIDBKeyFromValueAndKeyPath( | 366 IDBKey* key = createIDBKeyFromValueAndKeyPath(isolate, value, array[i], |
| 376 isolate, value, array[i], exceptionState, allowExperimentalTypes); | 367 exceptionState); |
| 377 if (!key) | 368 if (!key) |
| 378 return nullptr; | 369 return nullptr; |
| 379 result.push_back(key); | 370 result.push_back(key); |
| 380 } | 371 } |
| 381 return IDBKey::createArray(result); | 372 return IDBKey::createArray(result); |
| 382 } | 373 } |
| 383 | 374 |
| 384 ASSERT(keyPath.getType() == IDBKeyPath::StringType); | 375 ASSERT(keyPath.getType() == IDBKeyPath::StringType); |
| 385 return createIDBKeyFromValueAndKeyPath( | 376 return createIDBKeyFromValueAndKeyPath(isolate, value, keyPath.string(), |
| 386 isolate, value, keyPath.string(), exceptionState, allowExperimentalTypes); | 377 exceptionState); |
| 387 } | 378 } |
| 388 | 379 |
| 389 // Deserialize just the value data & blobInfo from the given IDBValue. | 380 // Deserialize just the value data & blobInfo from the given IDBValue. |
| 390 // Does not deserialize the key & keypath. | 381 // Does not deserialize the key & keypath. |
| 391 static v8::Local<v8::Value> deserializeIDBValueData(v8::Isolate* isolate, | 382 static v8::Local<v8::Value> deserializeIDBValueData(v8::Isolate* isolate, |
| 392 const IDBValue* value) { | 383 const IDBValue* value) { |
| 393 ASSERT(isolate->InContext()); | 384 ASSERT(isolate->InContext()); |
| 394 if (!value || value->isNull()) | 385 if (!value || value->isNull()) |
| 395 return v8::Null(isolate); | 386 return v8::Null(isolate); |
| 396 | 387 |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 // with implicit keys (i.e. a key path). It verifies that either the value | 589 // with implicit keys (i.e. a key path). It verifies that either the value |
| 599 // contains an implicit key matching the primary key (so it was correctly | 590 // contains an implicit key matching the primary key (so it was correctly |
| 600 // extracted when stored) or that the key can be inserted as an own property. | 591 // extracted when stored) or that the key can be inserted as an own property. |
| 601 void assertPrimaryKeyValidOrInjectable(ScriptState* scriptState, | 592 void assertPrimaryKeyValidOrInjectable(ScriptState* scriptState, |
| 602 const IDBValue* value) { | 593 const IDBValue* value) { |
| 603 ScriptState::Scope scope(scriptState); | 594 ScriptState::Scope scope(scriptState); |
| 604 v8::Isolate* isolate = scriptState->isolate(); | 595 v8::Isolate* isolate = scriptState->isolate(); |
| 605 ScriptValue keyValue = ScriptValue::from(scriptState, value->primaryKey()); | 596 ScriptValue keyValue = ScriptValue::from(scriptState, value->primaryKey()); |
| 606 ScriptValue scriptValue(scriptState, deserializeIDBValueData(isolate, value)); | 597 ScriptValue scriptValue(scriptState, deserializeIDBValueData(isolate, value)); |
| 607 | 598 |
| 608 // This assertion is about already persisted data, so allow experimental | |
| 609 // types. | |
| 610 const bool allowExperimentalTypes = true; | |
| 611 DummyExceptionStateForTesting exceptionState; | 599 DummyExceptionStateForTesting exceptionState; |
| 612 IDBKey* expectedKey = createIDBKeyFromValueAndKeyPath( | 600 IDBKey* expectedKey = createIDBKeyFromValueAndKeyPath( |
| 613 isolate, scriptValue.v8Value(), value->keyPath(), exceptionState, | 601 isolate, scriptValue.v8Value(), value->keyPath(), exceptionState); |
| 614 allowExperimentalTypes); | |
| 615 ASSERT(!exceptionState.hadException()); | 602 ASSERT(!exceptionState.hadException()); |
| 616 if (expectedKey && expectedKey->isEqual(value->primaryKey())) | 603 if (expectedKey && expectedKey->isEqual(value->primaryKey())) |
| 617 return; | 604 return; |
| 618 | 605 |
| 619 bool injected = injectV8KeyIntoV8Value( | 606 bool injected = injectV8KeyIntoV8Value( |
| 620 isolate, keyValue.v8Value(), scriptValue.v8Value(), value->keyPath()); | 607 isolate, keyValue.v8Value(), scriptValue.v8Value(), value->keyPath()); |
| 621 DCHECK(injected); | 608 DCHECK(injected); |
| 622 } | 609 } |
| 623 #endif | 610 #endif |
| 624 | 611 |
| 625 } // namespace blink | 612 } // namespace blink |
| OLD | NEW |