diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/bindings/js/IDBBindingUtilities.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/bindings/js/IDBBindingUtilities.cpp')
-rw-r--r-- | Source/WebCore/bindings/js/IDBBindingUtilities.cpp | 314 |
1 files changed, 199 insertions, 115 deletions
diff --git a/Source/WebCore/bindings/js/IDBBindingUtilities.cpp b/Source/WebCore/bindings/js/IDBBindingUtilities.cpp index 7a77db444..8fee1e297 100644 --- a/Source/WebCore/bindings/js/IDBBindingUtilities.cpp +++ b/Source/WebCore/bindings/js/IDBBindingUtilities.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. * Copyright (C) 2012 Michael Pruett <michael@68k.org> + * Copyright (C) 2014, 2015, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,14 +28,25 @@ #include "config.h" #if ENABLE(INDEXED_DATABASE) + #include "IDBBindingUtilities.h" -#include "DOMRequestState.h" +#include "IDBIndexInfo.h" #include "IDBKey.h" +#include "IDBKeyData.h" #include "IDBKeyPath.h" +#include "IDBValue.h" +#include "IndexKey.h" +#include "JSDOMBinding.h" +#include "JSDOMConvert.h" +#include "JSDOMStringList.h" #include "Logging.h" +#include "MessagePort.h" +#include "ScriptExecutionContext.h" +#include "SerializedScriptValue.h" #include "SharedBuffer.h" - +#include "ThreadSafeDataBuffer.h" +#include <runtime/ArrayBuffer.h> #include <runtime/DateInstance.h> #include <runtime/ObjectConstructor.h> @@ -42,18 +54,18 @@ using namespace JSC; namespace WebCore { -static bool get(ExecState* exec, JSValue object, const String& keyPathElement, JSValue& result) +static bool get(ExecState& exec, JSValue object, const String& keyPathElement, JSValue& result) { if (object.isString() && keyPathElement == "length") { - result = jsNumber(object.toString(exec)->length()); + result = jsNumber(asString(object)->length()); return true; } if (!object.isObject()) return false; - Identifier identifier(&exec->vm(), keyPathElement.utf8().data()); - if (!asObject(object)->hasProperty(exec, identifier)) + Identifier identifier = Identifier::fromString(&exec.vm(), keyPathElement); + if (!asObject(object)->hasProperty(&exec, identifier)) return false; - result = asObject(object)->get(exec, identifier); + result = asObject(object)->get(&exec, identifier); return true; } @@ -63,43 +75,64 @@ static bool canSet(JSValue object, const String& keyPathElement) return object.isObject(); } -static bool set(ExecState* exec, JSValue& object, const String& keyPathElement, JSValue jsValue) +static bool set(ExecState& exec, JSValue& object, const String& keyPathElement, JSValue jsValue) { if (!canSet(object, keyPathElement)) return false; - Identifier identifier(&exec->vm(), keyPathElement.utf8().data()); - asObject(object)->putDirect(exec->vm(), identifier, jsValue); + Identifier identifier = Identifier::fromString(&exec.vm(), keyPathElement); + asObject(object)->putDirect(exec.vm(), identifier, jsValue); return true; } -static JSValue idbKeyToJSValue(ExecState* exec, JSDOMGlobalObject* globalObject, IDBKey* key) +JSValue toJS(ExecState& state, JSGlobalObject& globalObject, IDBKey* key) { if (!key) { - // This should be undefined, not null. + // This must be undefined, not null. // Spec: http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBKeyRange return jsUndefined(); } + VM& vm = state.vm(); + Locker<JSLock> locker(vm.apiLock()); + auto scope = DECLARE_THROW_SCOPE(vm); + switch (key->type()) { - case IDBKey::ArrayType: - { - const IDBKey::KeyArray& inArray = key->array(); - size_t size = inArray.size(); - JSArray* outArray = constructEmptyArray(exec, 0, globalObject, size); - for (size_t i = 0; i < size; ++i) { - IDBKey* arrayKey = inArray.at(i).get(); - outArray->putDirectIndex(exec, i, idbKeyToJSValue(exec, globalObject, arrayKey)); - } - return JSValue(outArray); + case KeyType::Array: { + auto& inArray = key->array(); + unsigned size = inArray.size(); + auto outArray = constructEmptyArray(&state, 0, &globalObject, size); + RETURN_IF_EXCEPTION(scope, JSValue()); + for (size_t i = 0; i < size; ++i) { + outArray->putDirectIndex(&state, i, toJS(state, globalObject, inArray.at(i).get())); + RETURN_IF_EXCEPTION(scope, JSValue()); + } + return outArray; + } + case KeyType::Binary: { + auto* data = key->binary().data(); + if (!data) { + ASSERT_NOT_REACHED(); + return jsNull(); } - case IDBKey::StringType: - return jsStringWithCache(exec, key->string()); - case IDBKey::DateType: - return jsDateOrNull(exec, key->date()); - case IDBKey::NumberType: + + auto arrayBuffer = ArrayBuffer::create(data->data(), data->size()); + Structure* structure = globalObject.arrayBufferStructure(arrayBuffer->sharingMode()); + if (!structure) + return jsNull(); + + return JSArrayBuffer::create(state.vm(), structure, WTFMove(arrayBuffer)); + } + case KeyType::String: + return jsStringWithCache(&state, key->string()); + case KeyType::Date: + // FIXME: This should probably be toJS<IDLDate>(...) as per: + // http://w3c.github.io/IndexedDB/#request-convert-a-key-to-a-value + return toJS<IDLNullable<IDLDate>>(state, key->date()); + case KeyType::Number: return jsNumber(key->number()); - case IDBKey::MinType: - case IDBKey::InvalidType: + case KeyType::Min: + case KeyType::Max: + case KeyType::Invalid: ASSERT_NOT_REACHED(); return jsUndefined(); } @@ -110,29 +143,38 @@ static JSValue idbKeyToJSValue(ExecState* exec, JSDOMGlobalObject* globalObject, static const size_t maximumDepth = 2000; -static PassRefPtr<IDBKey> createIDBKeyFromValue(ExecState* exec, JSValue value, Vector<JSArray*>& stack) +static RefPtr<IDBKey> createIDBKeyFromValue(ExecState& exec, JSValue value, Vector<JSArray*>& stack) { - if (value.isNumber() && !std::isnan(value.toNumber(exec))) - return IDBKey::createNumber(value.toNumber(exec)); + VM& vm = exec.vm(); + if (value.isNumber() && !std::isnan(value.toNumber(&exec))) + return IDBKey::createNumber(value.toNumber(&exec)); + if (value.isString()) - return IDBKey::createString(value.toString(exec)->value(exec)); - if (value.inherits(DateInstance::info()) && !std::isnan(valueToDate(exec, value))) - return IDBKey::createDate(valueToDate(exec, value)); + return IDBKey::createString(asString(value)->value(&exec)); + + if (value.inherits(vm, DateInstance::info())) { + auto dateValue = valueToDate(exec, value); + if (!std::isnan(dateValue)) + return IDBKey::createDate(dateValue); + } + if (value.isObject()) { JSObject* object = asObject(value); - if (isJSArray(object) || object->inherits(JSArray::info())) { + if (isJSArray(object) || object->inherits(vm, JSArray::info())) { JSArray* array = asArray(object); size_t length = array->length(); if (stack.contains(array)) - return 0; + return nullptr; + if (stack.size() >= maximumDepth) - return 0; + return nullptr; + stack.append(array); - IDBKey::KeyArray subkeys; + Vector<RefPtr<IDBKey>> subkeys; for (size_t i = 0; i < length; i++) { - JSValue item = array->getIndex(exec, i); + JSValue item = array->getIndex(&exec, i); RefPtr<IDBKey> subkey = createIDBKeyFromValue(exec, item, stack); if (!subkey) subkeys.append(IDBKey::createInvalid()); @@ -143,30 +185,26 @@ static PassRefPtr<IDBKey> createIDBKeyFromValue(ExecState* exec, JSValue value, stack.removeLast(); return IDBKey::createArray(subkeys); } + + if (auto* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(vm, value)) + return IDBKey::createBinary(*arrayBuffer); + + if (auto* arrayBufferView = jsDynamicCast<JSArrayBufferView*>(vm, value)) + return IDBKey::createBinary(*arrayBufferView); } - return 0; + return nullptr; } -static PassRefPtr<IDBKey> createIDBKeyFromValue(ExecState* exec, JSValue value) +static Ref<IDBKey> createIDBKeyFromValue(ExecState& exec, JSValue value) { Vector<JSArray*> stack; RefPtr<IDBKey> key = createIDBKeyFromValue(exec, value, stack); if (key) - return key; + return *key; return IDBKey::createInvalid(); } -IDBKeyPath idbKeyPathFromValue(ExecState* exec, JSValue keyPathValue) -{ - IDBKeyPath keyPath; - if (isJSArray(keyPathValue)) - keyPath = IDBKeyPath(toNativeArray<String>(exec, keyPathValue)); - else - keyPath = IDBKeyPath(keyPathValue.toString(exec)->value(exec)); - return keyPath; -} - -static JSValue getNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) +static JSValue getNthValueOnKeyPath(ExecState& exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) { JSValue currentValue(rootValue); ASSERT(index <= keyPathElements.size()); @@ -178,21 +216,21 @@ static JSValue getNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const Ve return currentValue; } -static PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(ExecState* exec, const Deprecated::ScriptValue& value, const String& keyPath) +static RefPtr<IDBKey> internalCreateIDBKeyFromScriptValueAndKeyPath(ExecState& exec, const JSValue& value, const String& keyPath) { Vector<String> keyPathElements; IDBKeyPathParseError error; IDBParseKeyPath(keyPath, keyPathElements, error); - ASSERT(error == IDBKeyPathParseErrorNone); + ASSERT(error == IDBKeyPathParseError::None); - JSValue jsValue = value.jsValue(); + JSValue jsValue = value; jsValue = getNthValueOnKeyPath(exec, jsValue, keyPathElements, keyPathElements.size()); if (jsValue.isUndefined()) - return 0; + return nullptr; return createIDBKeyFromValue(exec, jsValue); } -static JSValue ensureNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) +static JSValue ensureNthValueOnKeyPath(ExecState& exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) { JSValue currentValue(rootValue); @@ -201,7 +239,7 @@ static JSValue ensureNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const JSValue parentValue(currentValue); const String& keyPathElement = keyPathElements[i]; if (!get(exec, parentValue, keyPathElement, currentValue)) { - JSObject* object = constructEmptyObject(exec); + JSObject* object = constructEmptyObject(&exec); if (!set(exec, parentValue, keyPathElement, JSValue(object))) return jsUndefined(); currentValue = JSValue(object); @@ -211,7 +249,7 @@ static JSValue ensureNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const return currentValue; } -static bool canInjectNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) +static bool canInjectNthValueOnKeyPath(ExecState& exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) { if (!rootValue.isObject()) return false; @@ -228,105 +266,151 @@ static bool canInjectNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const return true; } -bool injectIDBKeyIntoScriptValue(DOMRequestState* requestState, PassRefPtr<IDBKey> key, Deprecated::ScriptValue& value, const IDBKeyPath& keyPath) +bool injectIDBKeyIntoScriptValue(ExecState& exec, const IDBKeyData& keyData, JSValue value, const IDBKeyPath& keyPath) { - LOG(StorageAPI, "injectIDBKeyIntoScriptValue"); + LOG(IndexedDB, "injectIDBKeyIntoScriptValue"); - ASSERT(keyPath.type() == IDBKeyPath::StringType); + ASSERT(WTF::holds_alternative<String>(keyPath)); Vector<String> keyPathElements; IDBKeyPathParseError error; - IDBParseKeyPath(keyPath.string(), keyPathElements, error); - ASSERT(error == IDBKeyPathParseErrorNone); + IDBParseKeyPath(WTF::get<String>(keyPath), keyPathElements, error); + ASSERT(error == IDBKeyPathParseError::None); if (keyPathElements.isEmpty()) return false; - ExecState* exec = requestState->exec(); - - JSValue parent = ensureNthValueOnKeyPath(exec, value.jsValue(), keyPathElements, keyPathElements.size() - 1); + JSValue parent = ensureNthValueOnKeyPath(exec, value, keyPathElements, keyPathElements.size() - 1); if (parent.isUndefined()) return false; - if (!set(exec, parent, keyPathElements.last(), idbKeyToJSValue(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), key.get()))) + auto key = keyData.maybeCreateIDBKey(); + if (!key) + return false; + + if (!set(exec, parent, keyPathElements.last(), toJS(exec, *exec.lexicalGlobalObject(), key.get()))) return false; return true; } -PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(DOMRequestState* requestState, const Deprecated::ScriptValue& value, const IDBKeyPath& keyPath) -{ - LOG(StorageAPI, "createIDBKeyFromScriptValueAndKeyPath"); - ASSERT(!keyPath.isNull()); - ExecState* exec = requestState->exec(); - - if (keyPath.type() == IDBKeyPath::ArrayType) { - IDBKey::KeyArray result; - const Vector<String>& array = keyPath.array(); - for (size_t i = 0; i < array.size(); i++) { - RefPtr<IDBKey> key = createIDBKeyFromScriptValueAndKeyPath(exec, value, array[i]); +RefPtr<IDBKey> maybeCreateIDBKeyFromScriptValueAndKeyPath(ExecState& exec, const JSValue& value, const IDBKeyPath& keyPath) +{ + if (WTF::holds_alternative<Vector<String>>(keyPath)) { + auto& array = WTF::get<Vector<String>>(keyPath); + Vector<RefPtr<IDBKey>> result; + result.reserveInitialCapacity(array.size()); + for (auto& string : array) { + RefPtr<IDBKey> key = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, string); if (!key) - return 0; - result.append(key); + return nullptr; + result.uncheckedAppend(WTFMove(key)); } - return IDBKey::createArray(result); + return IDBKey::createArray(WTFMove(result)); } - ASSERT(keyPath.type() == IDBKeyPath::StringType); - return createIDBKeyFromScriptValueAndKeyPath(exec, value, keyPath.string()); + return internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, WTF::get<String>(keyPath)); } -bool canInjectIDBKeyIntoScriptValue(DOMRequestState* requestState, const Deprecated::ScriptValue& scriptValue, const IDBKeyPath& keyPath) +bool canInjectIDBKeyIntoScriptValue(ExecState& exec, const JSValue& scriptValue, const IDBKeyPath& keyPath) { LOG(StorageAPI, "canInjectIDBKeyIntoScriptValue"); - ASSERT(keyPath.type() == IDBKeyPath::StringType); + ASSERT(WTF::holds_alternative<String>(keyPath)); Vector<String> keyPathElements; IDBKeyPathParseError error; - IDBParseKeyPath(keyPath.string(), keyPathElements, error); - ASSERT(error == IDBKeyPathParseErrorNone); + IDBParseKeyPath(WTF::get<String>(keyPath), keyPathElements, error); + ASSERT(error == IDBKeyPathParseError::None); if (!keyPathElements.size()) return false; - JSC::ExecState* exec = requestState->exec(); - return canInjectNthValueOnKeyPath(exec, scriptValue.jsValue(), keyPathElements, keyPathElements.size() - 1); + return canInjectNthValueOnKeyPath(exec, scriptValue, keyPathElements, keyPathElements.size() - 1); +} + +static JSValue deserializeIDBValueToJSValue(ExecState& state, JSC::JSGlobalObject& globalObject, const IDBValue& value) +{ + // FIXME: I think it's peculiar to use undefined to mean "null data" and null to mean "empty data". + // But I am not changing this at the moment because at least some callers are specifically checking isUndefined. + + if (!value.data().data()) + return jsUndefined(); + + auto& data = *value.data().data(); + if (data.isEmpty()) + return jsNull(); + + auto serializedValue = SerializedScriptValue::createFromWireBytes(Vector<uint8_t>(data)); + + state.vm().apiLock().lock(); + Vector<RefPtr<MessagePort>> messagePorts; + JSValue result = serializedValue->deserialize(state, &globalObject, messagePorts, value.blobURLs(), value.blobFilePaths(), SerializationErrorMode::NonThrowing); + state.vm().apiLock().unlock(); + + return result; } -Deprecated::ScriptValue deserializeIDBValue(DOMRequestState* requestState, PassRefPtr<SerializedScriptValue> prpValue) +JSValue deserializeIDBValueToJSValue(ExecState& state, const IDBValue& value) { - ExecState* exec = requestState->exec(); - RefPtr<SerializedScriptValue> serializedValue = prpValue; - if (serializedValue) - return SerializedScriptValue::deserialize(exec, serializedValue.get(), NonThrowing); - return Deprecated::ScriptValue(exec->vm(), jsNull()); + return deserializeIDBValueToJSValue(state, *state.lexicalGlobalObject(), value); } -Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState* requestState, PassRefPtr<SharedBuffer> prpBuffer) +JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, const IDBValue& value) { - ExecState* exec = requestState->exec(); - RefPtr<SharedBuffer> buffer = prpBuffer; - if (buffer) { - // FIXME: The extra copy here can be eliminated by allowing SerializedScriptValue to take a raw const char* or const uint8_t*. - Vector<uint8_t> value; - value.append(buffer->data(), buffer->size()); - RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::createFromWireBytes(value); - return SerializedScriptValue::deserialize(exec, serializedValue.get(), NonThrowing); - } - return Deprecated::ScriptValue(exec->vm(), jsNull()); + ASSERT(state); + return deserializeIDBValueToJSValue(*state, *globalObject, value); } -Deprecated::ScriptValue idbKeyToScriptValue(DOMRequestState* requestState, PassRefPtr<IDBKey> key) +Ref<IDBKey> scriptValueToIDBKey(ExecState& exec, const JSValue& scriptValue) { - ExecState* exec = requestState->exec(); - return Deprecated::ScriptValue(exec->vm(), idbKeyToJSValue(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), key.get())); + return createIDBKeyFromValue(exec, scriptValue); } -PassRefPtr<IDBKey> scriptValueToIDBKey(DOMRequestState* requestState, const Deprecated::ScriptValue& scriptValue) +JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, const IDBKeyData& keyData) { - ExecState* exec = requestState->exec(); - return createIDBKeyFromValue(exec, scriptValue.jsValue()); + ASSERT(state); + ASSERT(globalObject); + + return toJS(*state, *globalObject, keyData.maybeCreateIDBKey().get()); +} + +static Vector<IDBKeyData> createKeyPathArray(ExecState& exec, JSValue value, const IDBIndexInfo& info) +{ + auto visitor = WTF::makeVisitor([&](const String& string) -> Vector<IDBKeyData> { + auto idbKey = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, string); + if (!idbKey) + return { }; + + Vector<IDBKeyData> keys; + if (info.multiEntry() && idbKey->type() == IndexedDB::Array) { + for (auto& key : idbKey->array()) + keys.append(key.get()); + } else + keys.append(idbKey.get()); + return keys; + }, [&](const Vector<String>& vector) -> Vector<IDBKeyData> { + Vector<IDBKeyData> keys; + for (auto& entry : vector) { + auto key = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, entry); + if (!key || !key->isValid()) + return { }; + keys.append(key.get()); + } + return keys; + }); + + return WTF::visit(visitor, info.keyPath()); +} + +void generateIndexKeyForValue(ExecState& exec, const IDBIndexInfo& info, JSValue value, IndexKey& outKey) +{ + auto keyDatas = createKeyPathArray(exec, value, info); + + if (keyDatas.isEmpty()) + return; + + outKey = IndexKey(WTFMove(keyDatas)); } } // namespace WebCore |