Blob type cannot be stored correctly in IDB when IDBObjectStore has autoIncrement...
authorsihui_liu@apple.com <sihui_liu@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Apr 2019 21:45:41 +0000 (21:45 +0000)
committersihui_liu@apple.com <sihui_liu@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Apr 2019 21:45:41 +0000 (21:45 +0000)
commit55c57e1b723773820a31fd4bd4f5c07b472c5df1
treef49a0fa75c8ff473ec2b9df9ea4aa482bc7a676b
parent56289f9d4663e0f002873fe7e76dcf7827c95f58
Blob type cannot be stored correctly in IDB when IDBObjectStore has autoIncrement and keyPath options
https://bugs.webkit.org/show_bug.cgi?id=196128
<rdar://problem/49562115>

Reviewed by Geoffrey Garen.

LayoutTests/imported/w3c:

Updated test expectations to PASS.

* web-platform-tests/IndexedDB/nested-cloning-large-expected.txt:
* web-platform-tests/IndexedDB/nested-cloning-large-multiple-expected.txt:
* web-platform-tests/IndexedDB/nested-cloning-small-expected.txt:

Source/WebCore:

If a key is auto-generated, it should become a property of the value object. Network process would perform the
key injection by deserializing IDBValue into script value, setting the property, serializing the result and
storing it in a database record. But network process does not have a JSDOMGlobalObject, so it would fail to
deserialize types including Blob and File.

To solve this issue, we move the key injection to web process and let network process store the original value
it gets. In this case, when web process asks for some value, network process should return key, value and key
path so that web process can decide whether it should perform a key injection before returning the result. Note
that the auto-generated key would always be stored as the key in a ObjectStore record.

Test: storage/indexeddb/modern/objectstore-autoincrement-types.html

* Modules/indexeddb/IDBCursor.cpp:
(WebCore::IDBCursor::setGetResult):
* Modules/indexeddb/IDBCursor.h:
(WebCore::IDBCursor::primaryKeyPath):
* Modules/indexeddb/IDBGetAllResult.cpp:
(WebCore::IDBGetAllResult::isolatedCopy):
(WebCore::IDBGetAllResult::addKey):
(WebCore::IDBGetAllResult::addValue):
(WebCore::IDBGetAllResult::keys const):
(WebCore::IDBGetAllResult::values const):
(WebCore::IDBGetAllResult::allBlobFilePaths const):
(WebCore::isolatedCopyOfVariant): Deleted.

* Modules/indexeddb/IDBGetAllResult.h: Introduce an IDBKeyPath parameter. Also replace Variant with two Vectors,
because we only needed to store either key or value before, and now the stored value could be incomplete.
(WebCore::IDBGetAllResult::IDBGetAllResult):
(WebCore::IDBGetAllResult::keyPath const):
(WebCore::IDBGetAllResult::encode const):
(WebCore::IDBGetAllResult::decode):

* Modules/indexeddb/IDBGetResult.cpp:
(WebCore::IDBGetResult::setValue):
* Modules/indexeddb/IDBGetResult.h:
(WebCore::IDBGetResult::IDBGetResult):
(WebCore::IDBGetResult::keyPath const):
* Modules/indexeddb/IDBRequest.cpp:
(WebCore::IDBRequest::setResult):
(WebCore::IDBRequest::setResultToStructuredClone):
* Modules/indexeddb/IDBRequest.h:
* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::didGetAllRecordsOnServer):
(WebCore::IDBTransaction::didGetRecordOnServer):
* Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
(WebCore::IDBServer::MemoryIDBBackingStore::getRecord):
* Modules/indexeddb/server/MemoryIndex.cpp:
(WebCore::IDBServer::MemoryIndex::getResultForKeyRange const):
(WebCore::IDBServer::MemoryIndex::getAllRecords const):
* Modules/indexeddb/server/MemoryIndexCursor.cpp:
(WebCore::IDBServer::MemoryIndexCursor::currentData):
* Modules/indexeddb/server/MemoryObjectStore.cpp:
(WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord):
(WebCore::IDBServer::MemoryObjectStore::populateIndexWithExistingRecords):
(WebCore::IDBServer::MemoryObjectStore::getAllRecords const):
* Modules/indexeddb/server/MemoryObjectStoreCursor.cpp:
(WebCore::IDBServer::MemoryObjectStoreCursor::currentData):
* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::updateOneIndexForAddRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::updateAllIndexesForAddRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::cachedStatementForGetAllObjectStoreRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getAllObjectStoreRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getAllIndexRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::uncheckedGetIndexRecordForOneKey):
(WebCore::IDBServer::SQLiteIDBBackingStore::openCursor):
(WebCore::IDBServer::SQLiteIDBBackingStore::iterateCursor):
* Modules/indexeddb/server/SQLiteIDBCursor.cpp:
(WebCore::IDBServer::SQLiteIDBCursor::currentData):
* Modules/indexeddb/server/SQLiteIDBCursor.h:
* Modules/indexeddb/server/UniqueIDBDatabase.cpp:

(WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd): Remove the key injection from network process.
UniqueIDBDatabase stores any value it gets from IDBClient.

* Modules/indexeddb/shared/IDBResultData.cpp:
(WebCore::IDBResultData::getResultRef):
* Modules/indexeddb/shared/IDBResultData.h:

* bindings/js/IDBBindingUtilities.cpp:
(WebCore::injectIDBKeyIntoScriptValue): If property is read-only, set would fail and injectKeyIntoResult would
return null, but we expect it to return result as long as the property value is the same as target. Therefore,
we can add an early return here.

(WebCore::createKeyPathArray):
(WebCore::generateIndexKeyForValue): We used to generate IndexKey from value stored in database but now the
value gets stored does not include auto-generated key, as we remove the key injection from network process. In
this case if the IDBIndex has the same key path as the auto-generated key, IndexKey would be failed to create
for it cannot extract auto-generated key from value. Since the auto-generated key would always be the key in
database record, we could use value of that key when we find a match in key path.

(WebCore::deserializeIDBValueWithKeyInjection): If the key path in the result is single entry, the key is
probably auto-generated, so we could inject the result key into the result value unconditionally.

* bindings/js/IDBBindingUtilities.h:
* bindings/js/JSIDBCursorWithValueCustom.cpp:
(WebCore::JSIDBCursorWithValue::value const):
* bindings/js/JSIDBRequestCustom.cpp:
(WebCore::JSIDBRequest::result const):

LayoutTests:

* storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt: Added.
* storage/indexeddb/modern/objectstore-autoincrement-types.html: Added.
* storage/indexeddb/modern/resources/objectstore-autoincrement-types.js: Added.
(prepareDatabase.event.target.onsuccess):
(prepareDatabase):
(compare):
(runGetTest):
(runGetAllTest):
(get store):
(testSteps):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244436 268f45cc-cd09-0410-ab3c-d52691b4dbfc
33 files changed:
LayoutTests/ChangeLog
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-expected.txt
LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-multiple-expected.txt
LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-small-expected.txt
LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/resources/objectstore-autoincrement-types.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBCursor.cpp
Source/WebCore/Modules/indexeddb/IDBCursor.h
Source/WebCore/Modules/indexeddb/IDBGetAllResult.cpp
Source/WebCore/Modules/indexeddb/IDBGetAllResult.h
Source/WebCore/Modules/indexeddb/IDBGetResult.cpp
Source/WebCore/Modules/indexeddb/IDBGetResult.h
Source/WebCore/Modules/indexeddb/IDBRequest.cpp
Source/WebCore/Modules/indexeddb/IDBRequest.h
Source/WebCore/Modules/indexeddb/IDBTransaction.cpp
Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp
Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp
Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp
Source/WebCore/Modules/indexeddb/server/MemoryObjectStoreCursor.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
Source/WebCore/Modules/indexeddb/shared/IDBResultData.cpp
Source/WebCore/Modules/indexeddb/shared/IDBResultData.h
Source/WebCore/bindings/js/IDBBindingUtilities.cpp
Source/WebCore/bindings/js/IDBBindingUtilities.h
Source/WebCore/bindings/js/JSIDBCursorWithValueCustom.cpp
Source/WebCore/bindings/js/JSIDBRequestCustom.cpp