summaryrefslogtreecommitdiff
path: root/Source/WebCore/bindings/js/IDBBindingUtilities.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/bindings/js/IDBBindingUtilities.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/bindings/js/IDBBindingUtilities.cpp')
-rw-r--r--Source/WebCore/bindings/js/IDBBindingUtilities.cpp314
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