PassRefPtr<IDBRequest> IDBObjectStore::put(IDBDatabaseBackend::PutMode putMode, PassRefPtr<IDBAny> source, JSC::ExecState* state, Deprecated::ScriptValue& value, const Deprecated::ScriptValue& keyValue, ExceptionCode& ec) { ScriptExecutionContext* context = scriptExecutionContextFromExecState(state); DOMRequestState requestState(context); RefPtr<IDBKey> key = scriptValueToIDBKey(&requestState, keyValue); return put(putMode, source, state, value, key.release(), ec); }
void InspectorController::didCallInjectedScriptFunction(JSC::ExecState* scriptState) { ASSERT(!m_injectedScriptInstrumentationCookies.isEmpty()); ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(scriptState); InspectorInstrumentationCookie cookie = m_injectedScriptInstrumentationCookies.takeLast(); InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext); }
void InspectorTimelineAgent::breakpointActionProbe(JSC::ExecState* exec, const Inspector::ScriptBreakpointAction& action, int hitCount, const Deprecated::ScriptValue&) { ASSERT(exec); ScriptExecutionContext* context = scriptExecutionContextFromExecState(exec); Document* document = (context && context->isDocument()) ? toDocument(context) : nullptr; Frame* frame = document ? document->frame() : nullptr; appendRecord(TimelineRecordFactory::createProbeSampleData(action, hitCount), TimelineRecordType::ProbeSample, false, frame); }
void InspectorController::willCallInjectedScriptFunction(JSC::ExecState* scriptState, const String& scriptName, int scriptLine) { ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(scriptState); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willCallFunction(scriptExecutionContext, scriptName, scriptLine); m_injectedScriptInstrumentationCookies.append(cookie); }
RefPtr<WebCore::IDBRequest> IDBObjectStore::putOrAdd(JSC::ExecState& state, JSC::JSValue value, RefPtr<IDBKey> key, IndexedDB::ObjectStoreOverwriteMode overwriteMode, ExceptionCode& ec) { LOG(IndexedDB, "IDBObjectStore::putOrAdd"); if (m_transaction->isReadOnly()) { ec = static_cast<ExceptionCode>(IDBExceptionCode::ReadOnlyError); return nullptr; } if (!m_transaction->isActive()) { ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError); return nullptr; } if (m_deleted) { ec = INVALID_STATE_ERR; return nullptr; } RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(&state, value, nullptr, nullptr); if (state.hadException()) { ec = DATA_CLONE_ERR; return nullptr; } if (serializedValue->hasBlobURLs()) { // FIXME: Add Blob/File/FileList support ec = DATA_CLONE_ERR; return nullptr; } if (key && key->type() == KeyType::Invalid) { ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError); return nullptr; } bool usesInlineKeys = !m_info.keyPath().isNull(); bool usesKeyGenerator = autoIncrement(); if (usesInlineKeys) { if (key) { ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError); return nullptr; } RefPtr<IDBKey> keyPathKey = maybeCreateIDBKeyFromScriptValueAndKeyPath(state, value, m_info.keyPath()); if (keyPathKey && !keyPathKey->isValid()) { ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError); return nullptr; } if (!keyPathKey) { if (usesKeyGenerator) { if (!canInjectIDBKeyIntoScriptValue(state, value, m_info.keyPath())) { ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError); return nullptr; } } else { ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError); return nullptr; } } if (keyPathKey) { ASSERT(!key); key = keyPathKey; } } else if (!usesKeyGenerator && !key) { ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError); return nullptr; } auto context = scriptExecutionContextFromExecState(&state); if (!context) { ec = static_cast<ExceptionCode>(IDBExceptionCode::Unknown); return nullptr; } Ref<IDBRequest> request = m_transaction->requestPutOrAdd(*context, *this, key.get(), *serializedValue, overwriteMode); return adoptRef(request.leakRef()); }
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(); }
JSValue JSWebKitSubtleCrypto::generateKey(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (state.argumentCount() < 1) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); RETURN_IF_EXCEPTION(scope, { }); auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); RETURN_IF_EXCEPTION(scope, { }); bool extractable = state.argument(1).toBoolean(&state); RETURN_IF_EXCEPTION(scope, { }); CryptoKeyUsageBitmap keyUsages = 0; if (state.argumentCount() >= 3) { keyUsages = cryptoKeyUsagesFromJSValue(state, scope, state.uncheckedArgument(2)); RETURN_IF_EXCEPTION(scope, { }); } RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); auto promise = wrapper->promise(); auto successCallback = [wrapper](KeyOrKeyPair&& keyOrKeyPair) mutable { WTF::switchOn(keyOrKeyPair, [&wrapper] (RefPtr<CryptoKey>& key) { wrapper->resolve<IDLInterface<CryptoKey>>(*key); }, [&wrapper] (CryptoKeyPair& keyPair) { wrapper->resolve<IDLDictionary<CryptoKeyPair>>(keyPair); } ); }; auto failureCallback = [wrapper]() mutable { wrapper->reject(); // FIXME: This should reject with an Exception. }; auto result = algorithm->generateKey(*parameters, extractable, keyUsages, WTFMove(successCallback), WTFMove(failureCallback), *scriptExecutionContextFromExecState(&state)); if (result.hasException()) { propagateException(state, scope, result.releaseException()); return { }; } return promise; }
JSValue JSWebKitSubtleCrypto::generateKey(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (state.argumentCount() < 1) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto algorithm = createAlgorithmFromJSValue(state, state.uncheckedArgument(0)); ASSERT(scope.exception() || algorithm); if (!algorithm) return jsUndefined(); auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(&state, algorithm->identifier(), state.uncheckedArgument(0)); ASSERT(scope.exception() || parameters); if (!parameters) return jsUndefined(); bool extractable = false; if (state.argumentCount() >= 2) { extractable = state.uncheckedArgument(1).toBoolean(&state); RETURN_IF_EXCEPTION(scope, JSValue()); } CryptoKeyUsageBitmap keyUsages = 0; if (state.argumentCount() >= 3) { auto success = cryptoKeyUsagesFromJSValue(state, state.argument(2), keyUsages); ASSERT(scope.exception() || success); if (!success) return jsUndefined(); } RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); auto promise = wrapper->promise(); auto successCallback = [wrapper](CryptoKey* key, CryptoKeyPair* keyPair) mutable { ASSERT(key || keyPair); ASSERT(!key || !keyPair); if (key) wrapper->resolve(key); else wrapper->resolve(keyPair); }; auto failureCallback = [wrapper]() mutable { wrapper->reject(nullptr); }; auto result = algorithm->generateKey(*parameters, extractable, keyUsages, WTFMove(successCallback), WTFMove(failureCallback), *scriptExecutionContextFromExecState(&state)); if (result.hasException()) { propagateException(state, scope, result.releaseException()); return { }; } return promise; }
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(); }
RefPtr<IDBRequest> IDBObjectStore::putOrAdd(ExecState& state, JSValue value, RefPtr<IDBKey> key, IndexedDB::ObjectStoreOverwriteMode overwriteMode, InlineKeyCheck inlineKeyCheck, ExceptionCodeWithMessage& ec) { LOG(IndexedDB, "IDBObjectStore::putOrAdd"); ASSERT(currentThread() == m_transaction->database().originThreadID()); auto context = scriptExecutionContextFromExecState(&state); if (!context) { ec.code = IDBDatabaseException::UnknownError; ec.message = ASCIILiteral("Unable to store record in object store because it does not have a valid script execution context"); return nullptr; } // The IDB spec for several IDBObjectStore methods states that transaction related exceptions should fire before // the exception for an object store being deleted. // However, a handful of W3C IDB tests expect the deleted exception even though the transaction inactive exception also applies. // Additionally, Chrome and Edge agree with the test, as does Legacy IDB in WebKit. // Until this is sorted out, we'll agree with the test and the majority share browsers. if (m_deleted) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The object store has been deleted."); return nullptr; } if (!m_transaction->isActive()) { ec.code = IDBDatabaseException::TransactionInactiveError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The transaction is inactive or finished."); return nullptr; } if (m_transaction->isReadOnly()) { ec.code = IDBDatabaseException::ReadOnlyError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The transaction is read-only."); return nullptr; } RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(&state, value, nullptr, nullptr); if (state.hadException()) { // Clear the DOM exception from the serializer so we can give a more targeted exception. state.clearException(); ec.code = IDBDatabaseException::DataCloneError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: An object could not be cloned."); return nullptr; } bool privateBrowsingEnabled = false; if (context->isDocument()) { if (auto* page = static_cast<Document*>(context)->page()) privateBrowsingEnabled = page->sessionID().isEphemeral(); } if (serializedValue->hasBlobURLs() && privateBrowsingEnabled) { // https://bugs.webkit.org/show_bug.cgi?id=156347 - Support Blobs in private browsing. ec.code = IDBDatabaseException::DataCloneError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: BlobURLs are not yet supported."); return nullptr; } if (key && !key->isValid()) { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The parameter is not a valid key."); return nullptr; } bool usesInlineKeys = !m_info.keyPath().isNull(); bool usesKeyGenerator = autoIncrement(); if (usesInlineKeys && inlineKeyCheck == InlineKeyCheck::Perform) { if (key) { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The object store uses in-line keys and the key parameter was provided."); return nullptr; } RefPtr<IDBKey> keyPathKey = maybeCreateIDBKeyFromScriptValueAndKeyPath(state, value, m_info.keyPath()); if (keyPathKey && !keyPathKey->isValid()) { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: Evaluating the object store's key path yielded a value that is not a valid key."); return nullptr; } if (!keyPathKey) { if (usesKeyGenerator) { if (!canInjectIDBKeyIntoScriptValue(state, value, m_info.keyPath())) { ec.code = IDBDatabaseException::DataError; return nullptr; } } else { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: Evaluating the object store's key path did not yield a value."); return nullptr; } } if (keyPathKey) { ASSERT(!key); key = keyPathKey; } } else if (!usesKeyGenerator && !key) { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The object store uses out-of-line keys and has no key generator and the key parameter was not provided."); return nullptr; } return m_transaction->requestPutOrAdd(*context, *this, key.get(), *serializedValue, overwriteMode); }
RefPtr<IDBRequest> IDBObjectStore::putOrAdd(JSC::ExecState& state, JSC::JSValue value, RefPtr<IDBKey> key, IndexedDB::ObjectStoreOverwriteMode overwriteMode, InlineKeyCheck inlineKeyCheck, ExceptionCodeWithMessage& ec) { LOG(IndexedDB, "IDBObjectStore::putOrAdd"); if (!m_transaction->isActive()) { ec.code = IDBDatabaseException::TransactionInactiveError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The transaction is inactive or finished."); return nullptr; } if (m_transaction->isReadOnly()) { ec.code = IDBDatabaseException::ReadOnlyError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The transaction is read-only."); return nullptr; } if (m_deleted) { ec.code = IDBDatabaseException::InvalidStateError; return nullptr; } RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(&state, value, nullptr, nullptr); if (state.hadException()) { ec.code = IDBDatabaseException::DataCloneError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: An object could not be cloned."); return nullptr; } if (serializedValue->hasBlobURLs()) { // FIXME: Add Blob/File/FileList support ec.code = IDBDatabaseException::DataCloneError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: BlobURLs are not yet supported."); return nullptr; } if (key && key->type() == KeyType::Invalid) { ec.code = IDBDatabaseException::DataError; return nullptr; } bool usesInlineKeys = !m_info.keyPath().isNull(); bool usesKeyGenerator = autoIncrement(); if (usesInlineKeys && inlineKeyCheck == InlineKeyCheck::Perform) { if (key) { ec.code = IDBDatabaseException::DataError; return nullptr; } RefPtr<IDBKey> keyPathKey = maybeCreateIDBKeyFromScriptValueAndKeyPath(state, value, m_info.keyPath()); if (keyPathKey && !keyPathKey->isValid()) { ec.code = IDBDatabaseException::DataError; return nullptr; } if (!keyPathKey) { if (usesKeyGenerator) { if (!canInjectIDBKeyIntoScriptValue(state, value, m_info.keyPath())) { ec.code = IDBDatabaseException::DataError; return nullptr; } } else { ec.code = IDBDatabaseException::DataError; return nullptr; } } if (keyPathKey) { ASSERT(!key); key = keyPathKey; } } else if (!usesKeyGenerator && !key) { ec.code = IDBDatabaseException::DataError; return nullptr; } auto context = scriptExecutionContextFromExecState(&state); if (!context) { ec.code = IDBDatabaseException::UnknownError; return nullptr; } Ref<IDBRequest> request = m_transaction->requestPutOrAdd(*context, *this, key.get(), *serializedValue, overwriteMode); return adoptRef(request.leakRef()); }