Exemplo n.º 1
0
PassRefPtr<IDBRequest> IDBCursor::update(ScriptState* state, ScriptValue& value, ExceptionCode& ec)
{
    IDB_TRACE("IDBCursor::update");

    if (!m_gotValue || isKeyCursor()) {
        ec = IDBDatabaseException::InvalidStateError;
        return 0;
    }
    if (!m_transaction->isActive()) {
        ec = IDBDatabaseException::TransactionInactiveError;
        return 0;
    }
    if (m_transaction->isReadOnly()) {
        ec = IDBDatabaseException::ReadOnlyError;
        return 0;
    }

    RefPtr<IDBObjectStore> objectStore = effectiveObjectStore();
    const IDBKeyPath& keyPath = objectStore->metadata().keyPath;
    const bool usesInLineKeys = !keyPath.isNull();
    if (usesInLineKeys) {
        RefPtr<IDBKey> keyPathKey = createIDBKeyFromScriptValueAndKeyPath(m_request->requestState(), value, keyPath);
        if (!keyPathKey || !keyPathKey->isEqual(m_currentPrimaryKey.get())) {
            ec = IDBDatabaseException::DataError;
            return 0;
        }
    }

    return objectStore->put(IDBObjectStoreBackendInterface::CursorUpdate, IDBAny::create(this), state, value, m_currentPrimaryKey, ec);
}
Exemplo n.º 2
0
void LegacyRequest::onSuccess(PassRefPtr<SharedBuffer> valueBuffer, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
{
    LOG(StorageAPI, "LegacyRequest::onSuccess(SharedBuffer, IDBKey, IDBKeyPath)");
    if (!shouldEnqueueEvent())
        return;

#ifndef NDEBUG
    ASSERT(keyPath == effectiveObjectStore(m_source.get())->keyPath());
#endif
    DOMRequestState::Scope scope(m_requestState);

    // FIXME: By not knowing whether or not the key is defined here, we don't know
    // if a null valueBuffer means the value is null or the value is undefined.
    Deprecated::ScriptValue value = deserializeIDBValueBuffer(requestState(), valueBuffer, true);

    RefPtr<IDBKey> primaryKey = prpPrimaryKey;

    if (!keyPath.isNull()) {
#ifndef NDEBUG
        RefPtr<IDBKey> expectedKey = createIDBKeyFromScriptValueAndKeyPath(requestState()->exec(), value, keyPath);
        ASSERT(!expectedKey || expectedKey->isEqual(primaryKey.get()));
#endif
        bool injected = injectIDBKeyIntoScriptValue(requestState(), primaryKey, value, keyPath);
        ASSERT_UNUSED(injected, injected);
    }

    onSuccessInternal(value);
}
Exemplo n.º 3
0
void IDBCursor::setValueReady(DOMRequestState* state, PassRefPtr<IDBKey> key, PassRefPtr<IDBKey> primaryKey, ScriptValue& value)
{
    m_currentKey = key;
    m_currentKeyValue = idbKeyToScriptValue(state, m_currentKey);

    m_currentPrimaryKey = primaryKey;
    m_currentPrimaryKeyValue = idbKeyToScriptValue(state, m_currentPrimaryKey);

    if (!isKeyCursor()) {
        RefPtr<IDBObjectStore> objectStore = effectiveObjectStore();
        const IDBObjectStoreMetadata metadata = objectStore->metadata();
        if (metadata.autoIncrement && !metadata.keyPath.isNull()) {
#ifndef NDEBUG
            RefPtr<IDBKey> expectedKey = createIDBKeyFromScriptValueAndKeyPath(m_request->requestState(), value, metadata.keyPath);
            ASSERT(!expectedKey || expectedKey->isEqual(m_currentPrimaryKey.get()));
#endif
            bool injected = injectIDBKeyIntoScriptValue(m_request->requestState(), m_currentPrimaryKey, value, metadata.keyPath);
            // FIXME: There is no way to report errors here. Move this into onSuccessWithContinuation so that we can abort the transaction there. See: https://bugs.webkit.org/show_bug.cgi?id=92278
            ASSERT_UNUSED(injected, injected);
        }
    }
    m_currentValue = value;

    m_gotValue = true;
}
Exemplo n.º 4
0
PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, ScriptValue& value, ExceptionCode& ec)
{
    IDB_TRACE("IDBCursor::update");

    if (!m_gotValue || isKeyCursor()) {
        ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
        return 0;
    }
    if (!m_transaction->isActive()) {
        ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
        return 0;
    }
    if (m_transaction->isReadOnly()) {
        ec = IDBDatabaseException::READ_ONLY_ERR;
        return 0;
    }

    RefPtr<IDBObjectStore> objectStore = effectiveObjectStore();
    const IDBKeyPath& keyPath = objectStore->metadata().keyPath;
    const bool usesInLineKeys = !keyPath.isNull();
    if (usesInLineKeys) {
        RefPtr<IDBKey> keyPathKey = createIDBKeyFromScriptValueAndKeyPath(value, keyPath);
        if (!keyPathKey || !keyPathKey->isEqual(m_currentPrimaryKey.get())) {
            ec = IDBDatabaseException::DATA_ERR;
            return 0;
        }
    }

    return objectStore->put(IDBObjectStoreBackendInterface::CursorUpdate, IDBAny::create(this), context, value, m_currentPrimaryKey, ec);
}
Exemplo n.º 5
0
PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(DOMRequestState* state, const ScriptValue& value, const IDBKeyPath& keyPath)
{
    IDB_TRACE("createIDBKeyFromScriptValueAndKeyPath");
    ASSERT(!keyPath.isNull());
    v8::Isolate* isolate = state ? state->context()->GetIsolate() : v8::Isolate::GetCurrent();
    ASSERT(isolate->InContext());
    v8::HandleScope handleScope(isolate);
    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(value, array[i], isolate);
            if (!key)
                return 0;
            result.append(key);
        }
        return IDBKey::createArray(result);
    }

    ASSERT(keyPath.type() == IDBKeyPath::StringType);
    return createIDBKeyFromScriptValueAndKeyPath(value, keyPath.string(), isolate);
}
Exemplo n.º 6
0
PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(DOMRequestState* requestState, const ScriptValue& value, const IDBKeyPath& keyPath)
{
    IDB_TRACE("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]);
            if (!key)
                return 0;
            result.append(key);
        }
        return IDBKey::createArray(result);
    }

    ASSERT(keyPath.type() == IDBKeyPath::StringType);
    return createIDBKeyFromScriptValueAndKeyPath(exec, value, keyPath.string());
}
Exemplo n.º 7
0
void assertPrimaryKeyValidOrInjectable(DOMRequestState* state, PassRefPtr<SharedBuffer> buffer, PassRefPtr<IDBKey> prpKey, const IDBKeyPath& keyPath)
{
    RefPtr<IDBKey> key(prpKey);

    DOMRequestState::Scope scope(*state);
    v8::Isolate* isolate = state ? state->context()->GetIsolate() : v8::Isolate::GetCurrent();

    ScriptValue keyValue = idbKeyToScriptValue(state, key);
    ScriptValue scriptValue(deserializeIDBValueBuffer(buffer.get(), isolate), isolate);

    RefPtr<IDBKey> expectedKey = createIDBKeyFromScriptValueAndKeyPath(state, scriptValue, keyPath);
    ASSERT(!expectedKey || expectedKey->isEqual(key.get()));

    bool injected = injectV8KeyIntoV8Value(keyValue.v8Value(), scriptValue.v8Value(), keyPath, isolate);
    ASSERT_UNUSED(injected, injected);
}
Exemplo n.º 8
0
IDBRequest* IDBCursor::update(ScriptState* scriptState, ScriptValue& value, ExceptionState& exceptionState)
{
    IDB_TRACE("IDBCursor::update");

    if (!m_gotValue) {
        exceptionState.throwDOMException(InvalidStateError, IDBDatabase::noValueErrorMessage);
        return 0;
    }
    if (isKeyCursor()) {
        exceptionState.throwDOMException(InvalidStateError, IDBDatabase::isKeyCursorErrorMessage);
        return 0;
    }
    if (isDeleted()) {
        exceptionState.throwDOMException(InvalidStateError, IDBDatabase::sourceDeletedErrorMessage);
        return 0;
    }
    if (m_transaction->isFinished() || m_transaction->isFinishing()) {
        exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
        return 0;
    }
    if (!m_transaction->isActive()) {
        exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
        return 0;
    }
    if (m_transaction->isReadOnly()) {
        exceptionState.throwDOMException(ReadOnlyError, "The record may not be updated inside a read-only transaction.");
        return 0;
    }

    IDBObjectStore* objectStore = effectiveObjectStore();
    const IDBKeyPath& keyPath = objectStore->metadata().keyPath;
    const bool usesInLineKeys = !keyPath.isNull();
    if (usesInLineKeys) {
        IDBKey* keyPathKey = createIDBKeyFromScriptValueAndKeyPath(scriptState->isolate(), value, keyPath);
        if (!keyPathKey || !keyPathKey->isEqual(m_primaryKey.get())) {
            exceptionState.throwDOMException(DataError, "The effective object store of this cursor uses in-line keys and evaluating the key path of the value parameter results in a different value than the cursor's effective key.");
            return 0;
        }
    }

    return objectStore->put(scriptState, blink::WebIDBPutModeCursorUpdate, IDBAny::create(this), value, m_primaryKey, exceptionState);
}
Exemplo n.º 9
0
void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> prpSerializedScriptValue, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
{
    IDB_TRACE("IDBRequest::onSuccess(SerializedScriptValue, IDBKey, IDBKeyPath)");
    if (!shouldEnqueueEvent())
        return;

#ifndef NDEBUG
    ASSERT(keyPath == effectiveObjectStore(m_source)->keyPath());
#endif
    ScriptValue value = deserializeIDBValue(scriptExecutionContext(), prpSerializedScriptValue);

    RefPtr<IDBKey> primaryKey = prpPrimaryKey;
#ifndef NDEBUG
    RefPtr<IDBKey> expectedKey = createIDBKeyFromScriptValueAndKeyPath(value, keyPath);
    ASSERT(!expectedKey || expectedKey->isEqual(primaryKey.get()));
#endif
    bool injected = injectIDBKeyIntoScriptValue(primaryKey, value, keyPath);
    ASSERT_UNUSED(injected, injected);
    onSuccessInternal(value);
}
Exemplo n.º 10
0
void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> valueBuffer, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
{
    IDB_TRACE("IDBRequest::onSuccess(SharedBuffer, IDBKey, IDBKeyPath)");
    if (!shouldEnqueueEvent())
        return;

#ifndef NDEBUG
    ASSERT(keyPath == effectiveObjectStore(m_source)->keyPath());
#endif
    DOMRequestState::Scope scope(m_requestState);
    ScriptValue value = deserializeIDBValueBuffer(requestState(), valueBuffer);

    RefPtr<IDBKey> primaryKey = prpPrimaryKey;
#ifndef NDEBUG
    RefPtr<IDBKey> expectedKey = createIDBKeyFromScriptValueAndKeyPath(requestState(), value, keyPath);
    ASSERT(!expectedKey || expectedKey->isEqual(primaryKey.get()));
#endif
    bool injected = injectIDBKeyIntoScriptValue(requestState(), primaryKey, value, keyPath);
    ASSERT_UNUSED(injected, injected);
    onSuccessInternal(value);
}
Exemplo n.º 11
0
static void generateIndexKeysForValue(DOMRequestState* requestState, const IDBIndexMetadata& indexMetadata, const Deprecated::ScriptValue& objectValue, IDBObjectStore::IndexKeys* indexKeys)
{
    ASSERT(indexKeys);
    RefPtr<IDBKey> indexKey = createIDBKeyFromScriptValueAndKeyPath(requestState, objectValue, indexMetadata.keyPath);

    if (!indexKey)
        return;

    if (!indexMetadata.multiEntry || indexKey->type() != IDBKey::ArrayType) {
        if (!indexKey->isValid())
            return;

        indexKeys->append(indexKey);
    } else {
        ASSERT(indexMetadata.multiEntry);
        ASSERT(indexKey->type() == IDBKey::ArrayType);
        indexKey = IDBKey::createMultiEntryArray(indexKey->array());

        for (size_t i = 0; i < indexKey->array().size(); ++i)
            indexKeys->append(indexKey->array()[i]);
    }
}
Exemplo n.º 12
0
void generateIndexKeysForValue(ExecState* exec, const IDBIndexMetadata& indexMetadata, const Deprecated::ScriptValue& objectValue, Vector<IDBKeyData>& indexKeys)
{
    RefPtr<IDBKey> indexKey = createIDBKeyFromScriptValueAndKeyPath(exec, objectValue, indexMetadata.keyPath);

    if (!indexKey)
        return;

    if (!indexMetadata.multiEntry || indexKey->type() != KeyType::Array) {
        if (!indexKey->isValid())
            return;

        indexKeys.append(IDBKeyData(indexKey.get()));
    } else {
        ASSERT(indexMetadata.multiEntry);
        ASSERT(indexKey->type() == KeyType::Array);
        indexKey = IDBKey::createMultiEntryArray(indexKey->array());

        if (!indexKey->isValid())
            return;

        for (auto& i : indexKey->array())
            indexKeys.append(IDBKeyData(i.get()));
    }
}
Exemplo n.º 13
0
PassRefPtr<IDBRequest> IDBObjectStore::put(IDBDatabaseBackend::PutMode putMode, PassRefPtr<IDBAny> source, JSC::ExecState* state, Deprecated::ScriptValue& value, PassRefPtr<IDBKey> prpKey, ExceptionCode& ec)
{
    RefPtr<IDBKey> key = prpKey;
    if (m_deleted) {
        ec = IDBDatabaseException::InvalidStateError;
        return 0;
    }
    if (!m_transaction->isActive()) {
        ec = IDBDatabaseException::TransactionInactiveError;
        return 0;
    }
    if (m_transaction->isReadOnly()) {
        ec = IDBDatabaseException::ReadOnlyError;
        return 0;
    }

    // FIXME: Expose the JS engine exception state through ScriptState.
    bool didThrow = false;
    RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::serialize(value, state, nullptr, nullptr, didThrow);
    if (didThrow) {
        // Setting an explicit ExceptionCode here would defer handling the already thrown exception.
        return 0;
    }

    if (serializedValue->hasBlobURLs()) {
        // FIXME: Add Blob/File/FileList support
        ec = IDBDatabaseException::DataCloneError;
        return 0;
    }

    const IDBKeyPath& keyPath = m_metadata.keyPath;
    const bool usesInLineKeys = !keyPath.isNull();
    const bool hasKeyGenerator = autoIncrement();

    ScriptExecutionContext* context = scriptExecutionContextFromExecState(state);
    DOMRequestState requestState(context);

    if (putMode != IDBDatabaseBackend::CursorUpdate && usesInLineKeys && key) {
        ec = IDBDatabaseException::DataError;
        return 0;
    }
    if (!usesInLineKeys && !hasKeyGenerator && !key) {
        ec = IDBDatabaseException::DataError;
        return 0;
    }
    if (usesInLineKeys) {
        RefPtr<IDBKey> keyPathKey = createIDBKeyFromScriptValueAndKeyPath(&requestState, value, keyPath);
        if (keyPathKey && !keyPathKey->isValid()) {
            ec = IDBDatabaseException::DataError;
            return 0;
        }
        if (!hasKeyGenerator && !keyPathKey) {
            ec = IDBDatabaseException::DataError;
            return 0;
        }
        if (hasKeyGenerator && !keyPathKey) {
            if (!canInjectIDBKeyIntoScriptValue(&requestState, value, keyPath)) {
                ec = IDBDatabaseException::DataError;
                return 0;
            }
        }
        if (keyPathKey)
            key = keyPathKey;
    }
    if (key && !key->isValid()) {
        ec = IDBDatabaseException::DataError;
        return 0;
    }

    Vector<int64_t> indexIds;
    Vector<IndexKeys> indexKeys;
    for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) {
        IndexKeys keys;
        generateIndexKeysForValue(&requestState, it->value, value, &keys);
        indexIds.append(it->key);
        indexKeys.append(keys);
    }

    RefPtr<IDBRequest> request = IDBRequest::create(context, source, m_transaction.get());
    Vector<uint8_t> valueBytes = serializedValue->toWireBytes();
    // This is a hack to account for disagreements about whether SerializedScriptValue should deal in Vector<uint8_t> or Vector<char>.
    // See https://lists.webkit.org/pipermail/webkit-dev/2013-February/023682.html
    Vector<char>* valueBytesSigned = reinterpret_cast<Vector<char>*>(&valueBytes);
    RefPtr<SharedBuffer> valueBuffer = SharedBuffer::adoptVector(*valueBytesSigned);
    backendDB()->put(m_transaction->id(), id(), valueBuffer, key.release(), static_cast<IDBDatabaseBackend::PutMode>(putMode), request, indexIds, indexKeys);
    return request.release();
}
Exemplo n.º 14
0
PassRefPtr<IDBRequest> IDBObjectStore::put(IDBDatabaseBackend::PutMode putMode, PassRefPtr<IDBAny> source, JSC::ExecState* state, Deprecated::ScriptValue& value, PassRefPtr<IDBKey> prpKey, ExceptionCode& ec)
{
    RefPtr<IDBKey> key = prpKey;
    if (m_deleted) {
        ec = IDBDatabaseException::InvalidStateError;
        return nullptr;
    }
    if (!m_transaction->isActive()) {
        ec = IDBDatabaseException::TransactionInactiveError;
        return nullptr;
    }
    if (m_transaction->isReadOnly()) {
        ec = IDBDatabaseException::ReadOnlyError;
        return nullptr;
    }

    RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(state, value.jsValue(), nullptr, nullptr);
    if (state->hadException())
        return nullptr;

    if (serializedValue->hasBlobURLs()) {
        // FIXME: Add Blob/File/FileList support
        ec = IDBDatabaseException::DataCloneError;
        return nullptr;
    }

    const IDBKeyPath& keyPath = m_metadata.keyPath;
    const bool usesInLineKeys = !keyPath.isNull();
    const bool hasKeyGenerator = autoIncrement();

    ScriptExecutionContext* context = scriptExecutionContextFromExecState(state);
    DOMRequestState requestState(context);

    if (putMode != IDBDatabaseBackend::CursorUpdate && usesInLineKeys && key) {
        ec = IDBDatabaseException::DataError;
        return nullptr;
    }
    if (!usesInLineKeys && !hasKeyGenerator && !key) {
        ec = IDBDatabaseException::DataError;
        return nullptr;
    }
    if (usesInLineKeys) {
        RefPtr<IDBKey> keyPathKey = createIDBKeyFromScriptValueAndKeyPath(requestState.exec(), value, keyPath);
        if (keyPathKey && !keyPathKey->isValid()) {
            ec = IDBDatabaseException::DataError;
            return nullptr;
        }
        if (!hasKeyGenerator && !keyPathKey) {
            ec = IDBDatabaseException::DataError;
            return nullptr;
        }
        if (hasKeyGenerator && !keyPathKey) {
            if (!canInjectIDBKeyIntoScriptValue(&requestState, value, keyPath)) {
                ec = IDBDatabaseException::DataError;
                return nullptr;
            }
        }
        if (keyPathKey)
            key = keyPathKey;
    }
    if (key && !key->isValid()) {
        ec = IDBDatabaseException::DataError;
        return nullptr;
    }

    Vector<int64_t> indexIds;
    Vector<IndexKeys> indexKeys;
    for (auto& index : m_metadata.indexes) {
        Vector<IDBKeyData> keyDatas;
        generateIndexKeysForValue(requestState.exec(), index.value, value, keyDatas);
        indexIds.append(index.key);

        // FIXME: Much of the Indexed DB code needs to use IDBKeyData directly to avoid wasteful conversions like this.
        Vector<RefPtr<IDBKey>> keys;
        for (auto& keyData : keyDatas) {
            RefPtr<IDBKey> key = keyData.maybeCreateIDBKey();
            if (key)
                keys.append(key.release());
        }
        indexKeys.append(keys);
    }

    RefPtr<IDBRequest> request = IDBRequest::create(context, source, m_transaction.get());
    Vector<uint8_t> valueBytes = serializedValue->toWireBytes();
    // This is a hack to account for disagreements about whether SerializedScriptValue should deal in Vector<uint8_t> or Vector<char>.
    // See https://lists.webkit.org/pipermail/webkit-dev/2013-February/023682.html
    Vector<char>* valueBytesSigned = reinterpret_cast<Vector<char>*>(&valueBytes);
    RefPtr<SharedBuffer> valueBuffer = SharedBuffer::adoptVector(*valueBytesSigned);
    backendDB()->put(m_transaction->id(), id(), valueBuffer, key.release(), static_cast<IDBDatabaseBackend::PutMode>(putMode), request, indexIds, indexKeys);
    return request.release();
}