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 |