Modern IDB (Blob support): Support retrieving Blobs from IDB.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Apr 2016 00:54:10 +0000 (00:54 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Apr 2016 00:54:10 +0000 (00:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=156367

Reviewed by Alex Christensen.

Source/WebCore:

No new tests (No testable change in behavior yet, current tests pass).

This patch does the following:
- Pulls BlobURLs and stored filenames out of IDB whenever an IDB record is fetched.
- Adds those URLs and filenames to IDBValue.
- Uses IDBValue in more places instead of SharedBuffer/ThreadSafeBuffer.
- Teaches SerializedScriptValue, Blob, and File how to read the URLs and filenames when they exist.
- Teaches the Blob registry to register a new type of Blob that is not a "File" but is backed by one.

* Modules/indexeddb/IDBCursor.cpp:
(WebCore::IDBCursor::setGetResult):

* Modules/indexeddb/IDBGetResult.h:
(WebCore::IDBGetResult::IDBGetResult):

* Modules/indexeddb/IDBRequest.cpp:
(WebCore::IDBRequest::setResultToStructuredClone):
* Modules/indexeddb/IDBRequest.h:

* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::didGetRecordOnServer):

* Modules/indexeddb/IDBValue.cpp:
(WebCore::IDBValue::IDBValue):
* Modules/indexeddb/IDBValue.h:

* Modules/indexeddb/server/MemoryIndexCursor.cpp:
(WebCore::IDBServer::MemoryIndexCursor::currentData):

* Modules/indexeddb/server/MemoryObjectStoreCursor.cpp:
(WebCore::IDBServer::MemoryObjectStoreCursor::currentData):

* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::createIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::getBlobRecordsForObjectStoreRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
* Modules/indexeddb/server/SQLiteIDBBackingStore.h:

* Modules/indexeddb/server/SQLiteIDBCursor.cpp:
(WebCore::IDBServer::SQLiteIDBCursor::currentData):
(WebCore::IDBServer::SQLiteIDBCursor::internalAdvanceOnce):
* Modules/indexeddb/server/SQLiteIDBCursor.h:
(WebCore::IDBServer::SQLiteIDBCursor::currentValue):
(WebCore::IDBServer::SQLiteIDBCursor::currentValueBuffer): Deleted.

* Modules/indexeddb/server/SQLiteIDBTransaction.h:
(WebCore::IDBServer::SQLiteIDBTransaction::backingStore):

* Modules/websockets/WorkerThreadableWebSocketChannel.cpp:
(WebCore::WorkerThreadableWebSocketChannel::Bridge::send):

* bindings/js/IDBBindingUtilities.cpp:
(WebCore::deserializeIDBValueDataToJSValue):
(WebCore::deserializeIDBValueData):
(WebCore::deserializeIDBValue):
* bindings/js/IDBBindingUtilities.h:

* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::deserialize):
(WebCore::CloneDeserializer::CloneDeserializer):
(WebCore::CloneDeserializer::readFile):
(WebCore::CloneDeserializer::readTerminal):
(WebCore::CloneDeserializer::blobFilePathForBlobURL):
(WebCore::SerializedScriptValue::deserialize):
* bindings/js/SerializedScriptValue.h:

* fileapi/Blob.cpp:
(WebCore::Blob::Blob):
* fileapi/Blob.h:
(WebCore::Blob::deserialize):

* fileapi/File.cpp:
(WebCore::File::File):

* fileapi/ThreadableBlobRegistry.cpp:
(WebCore::threadableQueue):
(WebCore::ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked):
* fileapi/ThreadableBlobRegistry.h:

* platform/CrossThreadTask.h:
(WebCore::createCrossThreadTask):

* platform/network/BlobRegistry.h:

* platform/network/BlobRegistryImpl.cpp:
(WebCore::BlobRegistryImpl::registerBlobURL):
(WebCore::BlobRegistryImpl::registerBlobURLOptionallyFileBacked):
* platform/network/BlobRegistryImpl.h:

Source/WebKit2:

* NetworkProcess/FileAPI/NetworkBlobRegistry.cpp:
(WebKit::NetworkBlobRegistry::registerBlobURLOptionallyFileBacked):
* NetworkProcess/FileAPI/NetworkBlobRegistry.h:

* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::registerBlobURLOptionallyFileBacked):
* NetworkProcess/NetworkConnectionToWebProcess.h:
* NetworkProcess/NetworkConnectionToWebProcess.messages.in:

* WebProcess/FileAPI/BlobRegistryProxy.cpp:
(WebKit::BlobRegistryProxy::registerBlobURLOptionallyFileBacked):
* WebProcess/FileAPI/BlobRegistryProxy.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@199524 268f45cc-cd09-0410-ab3c-d52691b4dbfc

37 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBCursor.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/IDBValue.cpp
Source/WebCore/Modules/indexeddb/IDBValue.h
Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp
Source/WebCore/Modules/indexeddb/server/MemoryObjectStoreCursor.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h
Source/WebCore/Modules/indexeddb/server/SQLiteIDBTransaction.h
Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.cpp
Source/WebCore/bindings/js/IDBBindingUtilities.cpp
Source/WebCore/bindings/js/IDBBindingUtilities.h
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/bindings/js/SerializedScriptValue.h
Source/WebCore/fileapi/Blob.cpp
Source/WebCore/fileapi/Blob.h
Source/WebCore/fileapi/File.cpp
Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
Source/WebCore/fileapi/ThreadableBlobRegistry.h
Source/WebCore/platform/CrossThreadTask.h
Source/WebCore/platform/network/BlobRegistry.h
Source/WebCore/platform/network/BlobRegistryImpl.cpp
Source/WebCore/platform/network/BlobRegistryImpl.h
Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp
Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.h
Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.cpp
Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.h
Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.messages.in
Source/WebKit2/WebProcess/FileAPI/BlobRegistryProxy.cpp
Source/WebKit2/WebProcess/FileAPI/BlobRegistryProxy.h

index 86a8416..6b32b0e 100644 (file)
@@ -1,3 +1,100 @@
+2016-04-13  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB (Blob support): Support retrieving Blobs from IDB.
+        https://bugs.webkit.org/show_bug.cgi?id=156367
+
+        Reviewed by Alex Christensen.
+
+        No new tests (No testable change in behavior yet, current tests pass).
+
+        This patch does the following:
+        - Pulls BlobURLs and stored filenames out of IDB whenever an IDB record is fetched.
+        - Adds those URLs and filenames to IDBValue.
+        - Uses IDBValue in more places instead of SharedBuffer/ThreadSafeBuffer.
+        - Teaches SerializedScriptValue, Blob, and File how to read the URLs and filenames when they exist.
+        - Teaches the Blob registry to register a new type of Blob that is not a "File" but is backed by one.
+
+        * Modules/indexeddb/IDBCursor.cpp:
+        (WebCore::IDBCursor::setGetResult):
+        
+        * Modules/indexeddb/IDBGetResult.h:
+        (WebCore::IDBGetResult::IDBGetResult):
+        
+        * Modules/indexeddb/IDBRequest.cpp:
+        (WebCore::IDBRequest::setResultToStructuredClone):
+        * Modules/indexeddb/IDBRequest.h:
+        
+        * Modules/indexeddb/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::didGetRecordOnServer):
+        
+        * Modules/indexeddb/IDBValue.cpp:
+        (WebCore::IDBValue::IDBValue):
+        * Modules/indexeddb/IDBValue.h:
+        
+        * Modules/indexeddb/server/MemoryIndexCursor.cpp:
+        (WebCore::IDBServer::MemoryIndexCursor::currentData):
+        
+        * Modules/indexeddb/server/MemoryObjectStoreCursor.cpp:
+        (WebCore::IDBServer::MemoryObjectStoreCursor::currentData):
+        
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
+        (WebCore::IDBServer::SQLiteIDBBackingStore::createIndex):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getBlobRecordsForObjectStoreRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.h:
+        
+        * Modules/indexeddb/server/SQLiteIDBCursor.cpp:
+        (WebCore::IDBServer::SQLiteIDBCursor::currentData):
+        (WebCore::IDBServer::SQLiteIDBCursor::internalAdvanceOnce):
+        * Modules/indexeddb/server/SQLiteIDBCursor.h:
+        (WebCore::IDBServer::SQLiteIDBCursor::currentValue):
+        (WebCore::IDBServer::SQLiteIDBCursor::currentValueBuffer): Deleted.
+        
+        * Modules/indexeddb/server/SQLiteIDBTransaction.h:
+        (WebCore::IDBServer::SQLiteIDBTransaction::backingStore):
+        
+        * Modules/websockets/WorkerThreadableWebSocketChannel.cpp:
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
+        
+        * bindings/js/IDBBindingUtilities.cpp:
+        (WebCore::deserializeIDBValueDataToJSValue):
+        (WebCore::deserializeIDBValueData):
+        (WebCore::deserializeIDBValue):
+        * bindings/js/IDBBindingUtilities.h:
+        
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::CloneDeserializer::deserialize):
+        (WebCore::CloneDeserializer::CloneDeserializer):
+        (WebCore::CloneDeserializer::readFile):
+        (WebCore::CloneDeserializer::readTerminal):
+        (WebCore::CloneDeserializer::blobFilePathForBlobURL):
+        (WebCore::SerializedScriptValue::deserialize):
+        * bindings/js/SerializedScriptValue.h:
+
+        * fileapi/Blob.cpp:
+        (WebCore::Blob::Blob):
+        * fileapi/Blob.h:
+        (WebCore::Blob::deserialize):
+
+        * fileapi/File.cpp:
+        (WebCore::File::File):
+
+        * fileapi/ThreadableBlobRegistry.cpp:
+        (WebCore::threadableQueue):
+        (WebCore::ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked):
+        * fileapi/ThreadableBlobRegistry.h:
+
+        * platform/CrossThreadTask.h:
+        (WebCore::createCrossThreadTask):
+
+        * platform/network/BlobRegistry.h:
+
+        * platform/network/BlobRegistryImpl.cpp:
+        (WebCore::BlobRegistryImpl::registerBlobURL):
+        (WebCore::BlobRegistryImpl::registerBlobURLOptionallyFileBacked):
+        * platform/network/BlobRegistryImpl.h:
+
 2016-04-13  Zalan Bujtas  <zalan@apple.com>
 
         Text on compositing layer with negative letter-spacing is truncated.
index 9980828..5ab0d9b 100644 (file)
@@ -418,7 +418,7 @@ void IDBCursor::setGetResult(IDBRequest& request, const IDBGetResult& getResult)
     if (isKeyCursor())
         m_deprecatedCurrentValue = { };
     else
-        m_deprecatedCurrentValue = deserializeIDBValueData(*context, getResult.value().data());
+        m_deprecatedCurrentValue = deserializeIDBValue(*context, getResult.value());
 
     m_gotValue = true;
 }
index d5b8680..65f5494 100644 (file)
@@ -43,10 +43,10 @@ public:
     {
     }
 
-    IDBGetResult(Ref<SharedBuffer>&& buffer, const IDBKeyData& currentPrimaryKey)
-        : m_primaryKeyData(currentPrimaryKey)
+    IDBGetResult(const IDBValue& value, const IDBKeyData& currentPrimaryKey)
+        : m_value(value)
+        , m_primaryKeyData(currentPrimaryKey)
     {
-        dataFromBuffer(buffer.get());
     }
 
     IDBGetResult(const ThreadSafeDataBuffer& buffer)
@@ -54,6 +54,11 @@ public:
     {
     }
 
+    IDBGetResult(IDBValue&& buffer)
+        : m_value(WTFMove(buffer))
+    {
+    }
+
     IDBGetResult(PassRefPtr<IDBKey> key)
         : m_keyData(key.get())
     {
@@ -78,8 +83,15 @@ public:
     {
     }
 
-    IDBGetResult(const IDBKeyData& keyData, const IDBKeyData& primaryKeyData, const ThreadSafeDataBuffer& valueBuffer)
-        : m_value(valueBuffer)
+    IDBGetResult(const IDBKeyData& keyData, const IDBKeyData& primaryKeyData, IDBValue&& value)
+        : m_value(WTFMove(value))
+        , m_keyData(keyData)
+        , m_primaryKeyData(primaryKeyData)
+    {
+    }
+
+    IDBGetResult(const IDBKeyData& keyData, const IDBKeyData& primaryKeyData, const IDBValue& value)
+        : m_value(value)
         , m_keyData(keyData)
         , m_primaryKeyData(primaryKeyData)
     {
@@ -97,7 +109,7 @@ public:
     template<class Decoder> static bool decode(Decoder&, IDBGetResult&);
 
 private:
-    WEBCORE_EXPORT void dataFromBuffer(SharedBuffer&);
+    void dataFromBuffer(SharedBuffer&);
 
     IDBValue m_value;
     IDBKeyData m_keyData;
index fe6950b..c4df90e 100644 (file)
@@ -341,7 +341,7 @@ void IDBRequest::setResult(uint64_t number)
     m_result = IDBAny::create(Deprecated::ScriptValue(scriptExecutionContext()->vm(), JSC::JSValue(number)));
 }
 
-void IDBRequest::setResultToStructuredClone(const ThreadSafeDataBuffer& valueData)
+void IDBRequest::setResultToStructuredClone(const IDBValue& value)
 {
     LOG(IndexedDB, "IDBRequest::setResultToStructuredClone");
 
@@ -349,8 +349,8 @@ void IDBRequest::setResultToStructuredClone(const ThreadSafeDataBuffer& valueDat
     if (!context)
         return;
 
-    Deprecated::ScriptValue value = deserializeIDBValueData(*context, valueData);
-    m_result = IDBAny::create(WTFMove(value));
+    Deprecated::ScriptValue scriptValue = deserializeIDBValue(*context, value);
+    m_result = IDBAny::create(WTFMove(scriptValue));
 }
 
 void IDBRequest::setResultToUndefined()
index e19023b..d0c0534 100644 (file)
@@ -44,6 +44,7 @@ class IDBIndex;
 class IDBKeyData;
 class IDBObjectStore;
 class IDBResultData;
+class IDBValue;
 class ThreadSafeDataBuffer;
 
 namespace IDBClient {
@@ -98,7 +99,7 @@ public:
 
     void setResult(const IDBKeyData*);
     void setResult(uint64_t);
-    void setResultToStructuredClone(const ThreadSafeDataBuffer&);
+    void setResultToStructuredClone(const IDBValue&);
     void setResultToUndefined();
 
     IDBAny* modernResult() { return m_result.get(); }
index 561563b..49b8518 100644 (file)
@@ -738,7 +738,7 @@ void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultDa
             request.setResultToUndefined();
     } else {
         if (resultData.getResult().value().data().data())
-            request.setResultToStructuredClone(resultData.getResult().value().data());
+            request.setResultToStructuredClone(resultData.getResult().value());
         else
             request.setResultToUndefined();
     }
index 51ca8ea..9fa626d 100644 (file)
@@ -54,6 +54,13 @@ IDBValue::IDBValue(const SerializedScriptValue& scriptValue, const Vector<String
 {
 }
 
+IDBValue::IDBValue(const ThreadSafeDataBuffer& value, Vector<String>&& blobURLs, Vector<String>&& blobFilePaths)
+    : m_data(value)
+    , m_blobURLs(WTFMove(blobURLs))
+    , m_blobFilePaths(WTFMove(blobFilePaths))
+{
+}
+
 IDBValue::IDBValue(const ThreadSafeDataBuffer& value, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths)
     : m_data(value)
     , m_blobURLs(blobURLs)
index 198c443..43ec4e4 100644 (file)
@@ -39,6 +39,7 @@ public:
     IDBValue(const SerializedScriptValue&);
     IDBValue(const ThreadSafeDataBuffer&);
     IDBValue(const SerializedScriptValue&, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths);
+    IDBValue(const ThreadSafeDataBuffer&, Vector<String>&& blobURLs, Vector<String>&& blobFilePaths);
     IDBValue(const ThreadSafeDataBuffer&, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths);
 
     IDBValue isolatedCopy() const;
index fec8106..2c73893 100644 (file)
@@ -74,8 +74,10 @@ void MemoryIndexCursor::currentData(IDBGetResult& getResult)
 
     if (m_info.cursorType() == IndexedDB::CursorType::KeyOnly)
         getResult = { m_currentKey, m_currentPrimaryKey };
-    else
-        getResult = { m_currentKey, m_currentPrimaryKey, m_index.objectStore().valueForKey(m_currentPrimaryKey) };
+    else {
+        IDBValue value = { m_index.objectStore().valueForKey(m_currentPrimaryKey), { }, { } };
+        getResult = { m_currentKey, m_currentPrimaryKey, WTFMove(value) };
+    }
 }
 
 void MemoryIndexCursor::iterate(const IDBKeyData& key, uint32_t count, IDBGetResult& getResult)
index 67cc68f..7d507cf 100644 (file)
@@ -189,7 +189,8 @@ void MemoryObjectStoreCursor::currentData(IDBGetResult& data)
     }
 
     m_currentPositionKey = **m_iterator;
-    data = { m_currentPositionKey, m_currentPositionKey, m_objectStore.valueForKeyRange(m_currentPositionKey) };
+    IDBValue value = { m_objectStore.valueForKeyRange(m_currentPositionKey), { }, { } };
+    data = { m_currentPositionKey, m_currentPositionKey, WTFMove(value) };
 }
 
 void MemoryObjectStoreCursor::incrementForwardIterator(std::set<IDBKeyData>& set, const IDBKeyData& key, uint32_t count)
index e78eb05..282a213 100644 (file)
@@ -1049,7 +1049,8 @@ IDBError SQLiteIDBBackingStore::createIndex(const IDBResourceIdentifier& transac
 
     while (!cursor->currentKey().isNull()) {
         auto& key = cursor->currentKey();
-        auto valueBuffer = ThreadSafeDataBuffer::copyVector(cursor->currentValueBuffer());
+        auto* value = cursor->currentValue();
+        ThreadSafeDataBuffer valueBuffer = value ? value->data() : ThreadSafeDataBuffer();
 
         IDBError error = updateOneIndexForAddRecord(info, key, valueBuffer);
         if (!error.isNull()) {
@@ -1627,6 +1628,60 @@ IDBError SQLiteIDBBackingStore::addRecord(const IDBResourceIdentifier& transacti
     return error;
 }
 
+IDBError SQLiteIDBBackingStore::getBlobRecordsForObjectStoreRecord(int64_t objectStoreRecord, Vector<String>& blobURLs, Vector<String>& blobFilePaths)
+{
+    ASSERT(objectStoreRecord);
+
+    HashSet<String> blobURLSet;
+    {
+        SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT blobURL FROM BlobRecords WHERE objectStoreRow = ?"));
+        if (sql.prepare() != SQLITE_OK
+            || sql.bindInt64(1, objectStoreRecord) != SQLITE_OK) {
+            LOG_ERROR("Could not prepare statement to fetch blob URLs for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up blobURL records in object store by key range") };
+        }
+
+        int sqlResult = sql.step();
+        if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE) {
+            // There are no blobURLs in the database for this object store record.
+            return { };
+        }
+
+        while (sqlResult == SQLITE_ROW) {
+            blobURLSet.add(sql.getColumnText(0));
+            sqlResult = sql.step();
+        }
+
+        if (sqlResult != SQLITE_DONE) {
+            LOG_ERROR("Could not fetch blob URLs for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up blobURL records in object store by key range") };
+        }
+    }
+
+    ASSERT(!blobURLSet.isEmpty());
+    String databaseDirectory = fullDatabaseDirectory();
+    for (auto& blobURL : blobURLSet) {
+        SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT fileName FROM BlobFiles WHERE blobURL = ?"));
+        if (sql.prepare() != SQLITE_OK
+            || sql.bindText(1, blobURL) != SQLITE_OK) {
+            LOG_ERROR("Could not prepare statement to fetch blob filename for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up blobURL records in object store by key range") };
+        }
+
+        if (sql.step() != SQLITE_ROW) {
+            LOG_ERROR("Entry for blob filename for blob url %s does not exist (%i) - %s", blobURL.utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up blobURL records in object store by key range") };
+        }
+
+        blobURLs.append(blobURL);
+
+        String fileName = sql.getColumnText(0);
+        blobFilePaths.append(pathByAppendingComponent(databaseDirectory, fileName));
+    }
+
+    return { };
+}
+
 IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange, IDBGetResult& resultValue)
 {
     LOG(IndexedDB, "SQLiteIDBBackingStore::getRecord - key range %s, object store %" PRIu64, keyRange.loggingString().utf8().data(), objectStoreID);
@@ -1658,11 +1713,13 @@ IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transacti
         return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize upper IDBKey in lookup range") };
     }
 
+    int64_t recordID = 0;
+    ThreadSafeDataBuffer resultBuffer;
     {
-        static NeverDestroyed<const ASCIILiteral> lowerOpenUpperOpen("SELECT value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
-        static NeverDestroyed<const ASCIILiteral> lowerOpenUpperClosed("SELECT value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
-        static NeverDestroyed<const ASCIILiteral> lowerClosedUpperOpen("SELECT value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
-        static NeverDestroyed<const ASCIILiteral> lowerClosedUpperClosed("SELECT value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<const ASCIILiteral> lowerOpenUpperOpen("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<const ASCIILiteral> lowerOpenUpperClosed("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<const ASCIILiteral> lowerClosedUpperOpen("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<const ASCIILiteral> lowerClosedUpperClosed("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
 
         const ASCIILiteral* query = nullptr;
 
@@ -1703,9 +1760,20 @@ IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transacti
 
         Vector<uint8_t> buffer;
         sql.getColumnBlobAsVector(0, buffer);
-        resultValue = ThreadSafeDataBuffer::adoptVector(buffer);
+        resultBuffer = ThreadSafeDataBuffer::adoptVector(buffer);
+
+        recordID = sql.getColumnInt64(1);
     }
 
+    ASSERT(recordID);
+    Vector<String> blobURLs, blobFilePaths;
+    auto error = getBlobRecordsForObjectStoreRecord(recordID, blobURLs, blobFilePaths);
+    ASSERT(blobURLs.size() == blobFilePaths.size());
+
+    if (!error.isNull())
+        return error;
+
+    resultValue = { { resultBuffer, WTFMove(blobURLs), WTFMove(blobFilePaths) } };
     return { };
 }
 
@@ -1739,7 +1807,7 @@ IDBError SQLiteIDBBackingStore::getIndexRecord(const IDBResourceIdentifier& tran
         if (type == IndexedDB::IndexRecordType::Key)
             getResult = { cursor->currentPrimaryKey() };
         else
-            getResult = { SharedBuffer::create(cursor->currentValueBuffer().data(), cursor->currentValueBuffer().size()), cursor->currentPrimaryKey() };
+            getResult = { cursor->currentValue() ? *cursor->currentValue() : IDBValue(), cursor->currentPrimaryKey() };
     }
 
     return { };
index de25a8b..35d4979 100644 (file)
@@ -85,6 +85,8 @@ public:
 
     IDBBackingStoreTemporaryFileHandler& temporaryFileHandler() const { return m_temporaryFileHandler; }
 
+    IDBError getBlobRecordsForObjectStoreRecord(int64_t objectStoreRecord, Vector<String>& blobURLs, Vector<String>& blobFilePaths);
+
 private:
     String filenameForDatabaseName() const;
     String fullDatabasePath() const;
index 641e44d..8de7cc1 100644 (file)
@@ -31,6 +31,7 @@
 #include "IDBGetResult.h"
 #include "IDBSerialization.h"
 #include "Logging.h"
+#include "SQLiteIDBBackingStore.h"
 #include "SQLiteIDBTransaction.h"
 #include "SQLiteStatement.h"
 #include "SQLiteTransaction.h"
@@ -102,7 +103,7 @@ void SQLiteIDBCursor::currentData(IDBGetResult& result)
         return;
     }
 
-    result = { m_currentKey, m_currentPrimaryKey, ThreadSafeDataBuffer::copyVector(m_currentValueBuffer) };
+    result = { m_currentKey, m_currentPrimaryKey, m_currentValue ? *m_currentValue : IDBValue() };
 }
 
 static String buildIndexStatement(const IDBKeyRangeData& keyRange, IndexedDB::CursorDirection cursorDirection)
@@ -337,6 +338,8 @@ SQLiteIDBCursor::AdvanceResult SQLiteIDBCursor::internalAdvanceOnce()
     ASSERT(m_statement);
     ASSERT(!m_completed);
 
+    m_currentValue = nullptr;
+
     int result = m_statement->step();
     if (result == SQLITE_DONE) {
         m_completed = true;
@@ -344,7 +347,7 @@ SQLiteIDBCursor::AdvanceResult SQLiteIDBCursor::internalAdvanceOnce()
         // When a cursor reaches its end, that is indicated by having undefined keys/values
         m_currentKey = IDBKeyData();
         m_currentPrimaryKey = IDBKeyData();
-        m_currentValueBuffer.clear();
+        m_currentValue = nullptr;
 
         return AdvanceResult::Success;
     }
@@ -367,12 +370,25 @@ SQLiteIDBCursor::AdvanceResult SQLiteIDBCursor::internalAdvanceOnce()
     }
 
     m_statement->getColumnBlobAsVector(2, keyData);
-    m_currentValueBuffer = keyData;
+
+    int64_t recordID = m_statement->getColumnInt64(0);
+    ASSERT(recordID);
 
     // The primaryKey of an ObjectStore cursor is the same as its key.
-    if (m_indexID == IDBIndexInfo::InvalidId)
+    if (m_indexID == IDBIndexInfo::InvalidId) {
         m_currentPrimaryKey = m_currentKey;
-    else {
+
+        Vector<String> blobURLs, blobFilePaths;
+        auto error = m_transaction->backingStore().getBlobRecordsForObjectStoreRecord(recordID, blobURLs, blobFilePaths);
+        if (!error.isNull()) {
+            LOG_ERROR("Unable to fetch blob records from database while advancing cursor");
+            m_completed = true;
+            m_errored = true;
+            return AdvanceResult::Failure;
+        }
+
+        m_currentValue = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData), blobURLs, blobFilePaths);
+    } else {
         if (!deserializeIDBKeyData(keyData.data(), keyData.size(), m_currentPrimaryKey)) {
             LOG_ERROR("Unable to deserialize value data from database while advancing index cursor");
             m_completed = true;
@@ -383,7 +399,7 @@ SQLiteIDBCursor::AdvanceResult SQLiteIDBCursor::internalAdvanceOnce()
         SQLiteStatement objectStoreStatement(m_statement->database(), "SELECT value FROM Records WHERE key = CAST(? AS TEXT) and objectStoreID = ?;");
 
         if (objectStoreStatement.prepare() != SQLITE_OK
-            || objectStoreStatement.bindBlob(1, m_currentValueBuffer.data(), m_currentValueBuffer.size()) != SQLITE_OK
+            || objectStoreStatement.bindBlob(1, keyData.data(), keyData.size()) != SQLITE_OK
             || objectStoreStatement.bindInt64(2, m_objectStoreID) != SQLITE_OK) {
             LOG_ERROR("Could not create index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg());
             m_completed = true;
@@ -393,9 +409,10 @@ SQLiteIDBCursor::AdvanceResult SQLiteIDBCursor::internalAdvanceOnce()
 
         int result = objectStoreStatement.step();
 
-        if (result == SQLITE_ROW)
-            objectStoreStatement.getColumnBlobAsVector(0, m_currentValueBuffer);
-        else if (result == SQLITE_DONE) {
+        if (result == SQLITE_ROW) {
+            objectStoreStatement.getColumnBlobAsVector(0, keyData);
+            m_currentValue = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData));
+        } else if (result == SQLITE_DONE) {
             // This indicates that the record we're trying to retrieve has been removed from the object store.
             // Skip over it.
             return AdvanceResult::ShouldAdvanceAgain;
index a841924..70a952b 100644 (file)
@@ -31,6 +31,7 @@
 #include "IDBKeyData.h"
 #include "IDBKeyRangeData.h"
 #include "IDBResourceIdentifier.h"
+#include "IDBValue.h"
 #include "SQLiteStatement.h"
 #include <wtf/Noncopyable.h>
 
@@ -61,7 +62,7 @@ public:
 
     const IDBKeyData& currentKey() const { return m_currentKey; }
     const IDBKeyData& currentPrimaryKey() const { return m_currentPrimaryKey; }
-    const Vector<uint8_t>& currentValueBuffer() const { return m_currentValueBuffer; }
+    IDBValue* currentValue() const { return m_currentValue.get(); }
 
     bool advance(uint64_t count);
     bool iterate(const IDBKeyData& targetKey);
@@ -102,7 +103,7 @@ private:
 
     IDBKeyData m_currentKey;
     IDBKeyData m_currentPrimaryKey;
-    Vector<uint8_t> m_currentValueBuffer;
+    std::unique_ptr<IDBValue> m_currentValue;
 
     std::unique_ptr<SQLiteStatement> m_statement;
     bool m_statementNeedsReset { false };
index fbffb88..1027d69 100644 (file)
@@ -70,6 +70,7 @@ public:
     bool inProgress() const;
 
     SQLiteTransaction* sqliteTransaction() const { return m_sqliteTransaction.get(); }
+    SQLiteIDBBackingStore& backingStore() { return m_backingStore; }
 
     void addBlobFile(const String& temporaryPath, const String& storedFilename);
     void addRemovedBlobFile(const String& removedFilename);
index 29f1d46..8a3bc47 100644 (file)
@@ -500,7 +500,7 @@ ThreadableWebSocketChannel::SendResult WorkerThreadableWebSocketChannel::Bridge:
         ASSERT_UNUSED(context, context.isDocument());
         ASSERT(peer);
 
-        peer->send(Blob::deserialize(capturedURL.url(), capturedType.string(), size));
+        peer->send(Blob::deserialize(capturedURL.url(), capturedType.string(), size, { }));
     });
 
     Ref<Bridge> protect(*this);
index 6717b1e..bcffd82 100644 (file)
@@ -34,6 +34,7 @@
 #include "IDBKey.h"
 #include "IDBKeyData.h"
 #include "IDBKeyPath.h"
+#include "IDBValue.h"
 #include "IndexKey.h"
 #include "JSDOMBinding.h"
 #include "Logging.h"
@@ -428,18 +429,7 @@ Deprecated::ScriptValue deserializeIDBValue(DOMRequestState* requestState, PassR
     return Deprecated::ScriptValue(exec->vm(), result);
 }
 
-Deprecated::ScriptValue deserializeIDBValueData(ScriptExecutionContext& context, const ThreadSafeDataBuffer& valueData)
-{
-    DOMRequestState state(&context);
-    auto* execState = state.exec();
-
-    if (!execState)
-        return Deprecated::ScriptValue();
-
-    return Deprecated::ScriptValue(execState->vm(), deserializeIDBValueDataToJSValue(*execState, valueData));
-}
-
-JSC::JSValue deserializeIDBValueDataToJSValue(JSC::ExecState& exec, const ThreadSafeDataBuffer& valueData)
+static JSC::JSValue deserializeIDBValueDataToJSValue(JSC::ExecState& exec, const ThreadSafeDataBuffer& valueData, const Vector<String> blobURLs, const Vector<String> blobFilePaths)
 {
     if (!valueData.data())
         return jsUndefined();
@@ -450,7 +440,7 @@ JSC::JSValue deserializeIDBValueDataToJSValue(JSC::ExecState& exec, const Thread
         RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::createFromWireBytes(Vector<uint8_t>(data));
 
         exec.vm().apiLock().lock();
-        result = serializedValue->deserialize(&exec, exec.lexicalGlobalObject(), 0, NonThrowing);
+        result = serializedValue->deserialize(&exec, exec.lexicalGlobalObject(), 0, NonThrowing, blobURLs, blobFilePaths);
         exec.vm().apiLock().unlock();
     } else
         result = jsNull();
@@ -458,6 +448,34 @@ JSC::JSValue deserializeIDBValueDataToJSValue(JSC::ExecState& exec, const Thread
     return result;
 }
 
+Deprecated::ScriptValue deserializeIDBValueData(ScriptExecutionContext& context, const ThreadSafeDataBuffer& valueData)
+{
+    DOMRequestState state(&context);
+    auto* execState = state.exec();
+
+    if (!execState)
+        return { };
+
+    return { execState->vm(), deserializeIDBValueDataToJSValue(*execState, valueData) };
+}
+
+Deprecated::ScriptValue deserializeIDBValue(ScriptExecutionContext& context, const IDBValue& value)
+{
+    DOMRequestState state(&context);
+    auto* execState = state.exec();
+
+    if (!execState)
+        return { };
+
+    return { execState->vm(), deserializeIDBValueDataToJSValue(*execState, value.data(), value.blobURLs(), value.blobFilePaths()) };
+}
+
+JSC::JSValue deserializeIDBValueDataToJSValue(JSC::ExecState& exec, const ThreadSafeDataBuffer& valueData)
+{
+    Vector<String> dummyURLs, dummyFilePaths;
+    return deserializeIDBValueDataToJSValue(exec, valueData, dummyURLs, dummyFilePaths);
+}
+
 Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState* requestState, PassRefPtr<SharedBuffer> prpBuffer, bool keyIsDefined)
 {
     if (prpBuffer) {
index c170d16..1150bcd 100644 (file)
@@ -39,6 +39,7 @@ class IDBIndexInfo;
 class IDBKey;
 class IDBKeyData;
 class IDBKeyPath;
+class IDBValue;
 class IndexKey;
 class SharedBuffer;
 class ThreadSafeDataBuffer;
@@ -57,6 +58,7 @@ bool canInjectIDBKeyIntoScriptValue(JSC::ExecState&, const JSC::JSValue&, const
 
 Deprecated::ScriptValue deserializeIDBValue(DOMRequestState*, PassRefPtr<SerializedScriptValue>);
 Deprecated::ScriptValue deserializeIDBValueData(ScriptExecutionContext&, const ThreadSafeDataBuffer& valueData);
+Deprecated::ScriptValue deserializeIDBValue(ScriptExecutionContext&, const IDBValue&);
 Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState*, PassRefPtr<SharedBuffer>, bool keyIsDefined);
 WEBCORE_EXPORT Deprecated::ScriptValue deserializeIDBValueBuffer(JSC::ExecState*, Vector<uint8_t>&&, bool keyIsDefined);
 
index 5e836d0..87002ef 100644 (file)
@@ -1482,13 +1482,11 @@ public:
         return str;
     }
 
-    static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject,
-                                             MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray,
-                                             const Vector<uint8_t>& buffer)
+    static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths)
     {
         if (!buffer.size())
             return std::make_pair(jsNull(), UnspecifiedError);
-        CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer);
+        CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer, blobURLs, blobFilePaths);
         if (!deserializer.isValid())
             return std::make_pair(JSValue(), ValidationError);
         return deserializer.deserialize();
@@ -1533,9 +1531,7 @@ private:
         size_t m_index;
     };
 
-    CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, 
-                      MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents,
-                      const Vector<uint8_t>& buffer)
+    CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer)
         : CloneBase(exec)
         , m_globalObject(globalObject)
         , m_isDOMGlobalObject(globalObject->inherits(JSDOMGlobalObject::info()))
@@ -1550,6 +1546,23 @@ private:
             m_version = 0xFFFFFFFF;
     }
 
+    CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths)
+        : CloneBase(exec)
+        , m_globalObject(globalObject)
+        , m_isDOMGlobalObject(globalObject->inherits(JSDOMGlobalObject::info()))
+        , m_ptr(buffer.data())
+        , m_end(buffer.data() + buffer.size())
+        , m_version(0xFFFFFFFF)
+        , m_messagePorts(messagePorts)
+        , m_arrayBufferContents(arrayBufferContents)
+        , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
+        , m_blobURLs(blobURLs)
+        , m_blobFilePaths(blobFilePaths)
+    {
+        if (!read(m_version))
+            m_version = 0xFFFFFFFF;
+    }
+
     DeserializationResult deserialize();
 
     void throwValidationError()
@@ -1773,8 +1786,14 @@ private:
         CachedStringRef name;
         if (!readStringData(name))
             return 0;
+
+        // If the blob URL for this file has an associated blob file path, prefer that one over the "built-in" path.
+        String filePath = blobFilePathForBlobURL(url->string());
+        if (filePath.isEmpty())
+            filePath = path->string();
+
         if (m_isDOMGlobalObject)
-            file = File::deserialize(path->string(), URL(URL(), url->string()), type->string(), name->string());
+            file = File::deserialize(filePath, URL(URL(), url->string()), type->string(), name->string());
         return true;
     }
 
@@ -2273,7 +2292,7 @@ private:
                 return JSValue();
             if (!m_isDOMGlobalObject)
                 return jsNull();
-            return getJSValue(Blob::deserialize(URL(URL(), url->string()), type->string(), size).get());
+            return getJSValue(Blob::deserialize(URL(URL(), url->string()), type->string(), size, blobFilePathForBlobURL(url->string())).get());
         }
         case StringTag: {
             CachedStringRef cachedString;
@@ -2405,6 +2424,19 @@ private:
     MessagePortArray* m_messagePorts;
     ArrayBufferContentsArray* m_arrayBufferContents;
     ArrayBufferArray m_arrayBuffers;
+    Vector<String> m_blobURLs;
+    Vector<String> m_blobFilePaths;
+
+    String blobFilePathForBlobURL(const String& blobURL)
+    {
+        size_t i = 0;
+        for (; i < m_blobURLs.size(); ++i) {
+            if (m_blobURLs[i] == blobURL)
+                break;
+        }
+
+        return i < m_blobURLs.size() ? m_blobFilePaths[i] : String();
+    }
 };
 
 DeserializationResult CloneDeserializer::deserialize()
@@ -2683,11 +2715,15 @@ String SerializedScriptValue::toString()
     return CloneDeserializer::deserializeString(m_data);
 }
 
-JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject,
-                                           MessagePortArray* messagePorts, SerializationErrorMode throwExceptions)
+JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject, MessagePortArray* messagePorts, SerializationErrorMode throwExceptions)
+{
+    Vector<String> dummyBlobs, dummyPaths;
+    return deserialize(exec, globalObject, messagePorts, throwExceptions, dummyBlobs, dummyPaths);
+}
+
+JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject, MessagePortArray* messagePorts, SerializationErrorMode throwExceptions, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths)
 {
-    DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts,
-                                                                  m_arrayBufferContentsArray.get(), m_data);
+    DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts, m_arrayBufferContentsArray.get(), m_data, blobURLs, blobFilePaths);
     if (throwExceptions == Throwing)
         maybeThrowExceptionIfSerializationFailed(exec, result.second);
     return result.first ? result.first : jsNull();
index 15cbf8a..bcd2d55 100644 (file)
@@ -73,6 +73,7 @@ public:
     static Ref<SerializedScriptValue> nullValue();
 
     WEBCORE_EXPORT JSC::JSValue deserialize(JSC::ExecState*, JSC::JSGlobalObject*, MessagePortArray*, SerializationErrorMode = Throwing);
+    JSC::JSValue deserialize(JSC::ExecState*, JSC::JSGlobalObject*, MessagePortArray*, SerializationErrorMode, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths);
 
     static uint32_t wireFormatVersion();
 
index b2f2282..d9cbb7f 100644 (file)
@@ -95,12 +95,15 @@ Blob::Blob(Vector<BlobPart> blobParts, const String& contentType)
     ThreadableBlobRegistry::registerBlobURL(m_internalURL, WTFMove(blobParts), contentType);
 }
 
-Blob::Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size)
+Blob::Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size, const String& fileBackedPath)
     : m_type(normalizedContentType(type))
     , m_size(size)
 {
     m_internalURL = BlobURL::createInternalURL();
-    ThreadableBlobRegistry::registerBlobURL(nullptr, m_internalURL, srcURL);
+    if (fileBackedPath.isEmpty())
+        ThreadableBlobRegistry::registerBlobURL(nullptr, m_internalURL, srcURL);
+    else
+        ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(m_internalURL, srcURL, fileBackedPath);
 }
 
 Blob::Blob(const URL& srcURL, long long start, long long end, const String& type)
index 93333dc..49b6d07 100644 (file)
@@ -58,10 +58,10 @@ public:
         return adoptRef(*new Blob(WTFMove(blobParts), contentType));
     }
 
-    static Ref<Blob> deserialize(const URL& srcURL, const String& type, long long size)
+    static Ref<Blob> deserialize(const URL& srcURL, const String& type, long long size, const String& fileBackedPath)
     {
         ASSERT(Blob::isNormalizedContentType(type));
-        return adoptRef(*new Blob(deserializationContructor, srcURL, type, size));
+        return adoptRef(*new Blob(deserializationContructor, srcURL, type, size, fileBackedPath));
     }
 
     virtual ~Blob();
@@ -98,7 +98,7 @@ protected:
     Blob(UninitializedContructor);
 
     enum DeserializationContructor { deserializationContructor };
-    Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size);
+    Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size, const String& fileBackedPath);
 
     // For slicing.
     Blob(const URL& srcURL, long long start, long long end, const String& contentType);
index 94b2288..8bba87f 100644 (file)
@@ -58,7 +58,7 @@ File::File(const String& path, const String& nameOverride)
 }
 
 File::File(DeserializationContructor, const String& path, const URL& url, const String& type, const String& name)
-    : Blob(deserializationContructor, url, type, -1)
+    : Blob(deserializationContructor, url, type, -1, path)
     , m_path(path)
     , m_name(name)
 {
index 71880ca..a5451ae 100644 (file)
 #include "BlobPart.h"
 #include "BlobRegistry.h"
 #include "BlobURL.h"
+#include "CrossThreadTask.h"
 #include "SecurityOrigin.h"
 #include <mutex>
 #include <wtf/HashMap.h>
 #include <wtf/MainThread.h>
+#include <wtf/MessageQueue.h>
 #include <wtf/RefPtr.h>
 #include <wtf/ThreadSpecific.h>
 #include <wtf/text/StringHash.h>
@@ -98,6 +100,17 @@ static ThreadSpecific<BlobUrlOriginMap>& originMap()
     return *map;
 }
 
+static MessageQueue<CrossThreadTask>& threadableQueue()
+{
+    static std::once_flag onceFlag;
+    static MessageQueue<CrossThreadTask>* queue;
+    std::call_once(onceFlag, [] {
+        queue = new MessageQueue<CrossThreadTask>;
+    });
+
+    return *queue;
+}
+
 void ThreadableBlobRegistry::registerFileBlobURL(const URL& url, const String& path, const String& contentType)
 {
     if (isMainThread())
@@ -144,6 +157,21 @@ void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, const URL&
     }
 }
 
+void ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath)
+{
+    if (isMainThread())
+        blobRegistry().registerBlobURLOptionallyFileBacked(url, srcURL, fileBackedPath);
+    else {
+        threadableQueue().append(createCrossThreadTask(ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked, url, srcURL, fileBackedPath));
+
+        callOnMainThread([] {
+            auto task = threadableQueue().tryGetMessage();
+            ASSERT(task);
+            task->performTask();
+        });
+    }
+}
+
 void ThreadableBlobRegistry::registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end)
 {
     if (isMainThread())
index 8ec9764..97099b6 100644 (file)
@@ -45,6 +45,7 @@ public:
     static void registerFileBlobURL(const URL&, const String& path, const String& contentType);
     static void registerBlobURL(const URL&, Vector<BlobPart> blobParts, const String& contentType);
     static void registerBlobURL(SecurityOrigin*, const URL&, const URL& srcURL);
+    static void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, const String& fileBackedPath);
     static void registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end);
     static void unregisterBlobURL(const URL&);
 
index f8dec44..b823bc1 100644 (file)
@@ -62,6 +62,17 @@ public:
     }
 };
 
+template <typename... Arguments>
+class CrossThreadTaskStaticImpl final : public CrossThreadTask {
+public:
+    CrossThreadTaskStaticImpl(void (*method)(Arguments...), Arguments&&... arguments)
+    {
+        m_taskFunction = [method, arguments...] {
+            method(arguments...);
+        };
+    }
+};
+
 template<typename T>
 std::unique_ptr<CrossThreadTask> createCrossThreadTask(
     T& callee,
@@ -113,6 +124,20 @@ std::unique_ptr<CrossThreadTask> createCrossThreadTask(
         WebCore::CrossThreadCopier<P3>::copy(parameter3));
 }
 
+template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3>
+std::unique_ptr<CrossThreadTask> createCrossThreadTask(
+    void (*method)(MP1, MP2, MP3),
+    const P1& parameter1,
+    const P2& parameter2,
+    const P3& parameter3)
+{
+    return std::make_unique<CrossThreadTaskStaticImpl<MP1, MP2, MP3>>(
+        method,
+        WebCore::CrossThreadCopier<P1>::copy(parameter1),
+        WebCore::CrossThreadCopier<P2>::copy(parameter2),
+        WebCore::CrossThreadCopier<P3>::copy(parameter3));
+}
+
 template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4>
 std::unique_ptr<CrossThreadTask> createCrossThreadTask(
     T& callee,
index 842e82b..41a8087 100644 (file)
@@ -57,6 +57,9 @@ public:
     // Registers a new blob URL referring to the blob data identified by the specified srcURL.
     virtual void registerBlobURL(const URL&, const URL& srcURL) = 0;
 
+    // Registers a new blob URL referring to the blob data identified by the specified srcURL or, if none found, referring to the file found at the given path.
+    virtual void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, const String& fileBackedPath) = 0;
+
     // Negative start and end values select from the end.
     virtual void registerBlobURLForSlice(const URL&, const URL& srcURL, long long start, long long end) = 0;
 
index dcb78bc..338d1b3 100644 (file)
@@ -160,13 +160,26 @@ void BlobRegistryImpl::registerBlobURL(const URL& url, Vector<BlobPart> blobPart
 
 void BlobRegistryImpl::registerBlobURL(const URL& url, const URL& srcURL)
 {
+    registerBlobURLOptionallyFileBacked(url, srcURL, { });
+}
+
+void BlobRegistryImpl::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath)
+{
     ASSERT(isMainThread());
 
     BlobData* src = getBlobDataFromURL(srcURL);
-    if (!src)
+    if (src) {
+        m_blobs.set(url.string(), src);
         return;
+    }
+
+    if (fileBackedPath.isEmpty())
+        return;
+
+    RefPtr<BlobData> backingFile = BlobData::create({ });
+    backingFile->appendFile(BlobDataFileReference::create(fileBackedPath));
 
-    m_blobs.set(url.string(), src);
+    m_blobs.set(url.string(), backingFile.release());
 }
 
 void BlobRegistryImpl::registerBlobURLForSlice(const URL& url, const URL& srcURL, long long start, long long end)
index c6006db..5006a58 100644 (file)
@@ -61,6 +61,7 @@ private:
     void registerFileBlobURL(const URL&, RefPtr<BlobDataFileReference>&&, const String& contentType) override;
     void registerBlobURL(const URL&, Vector<BlobPart>, const String& contentType) override;
     void registerBlobURL(const URL&, const URL& srcURL) override;
+    void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, const String& fileBackedPath) override;
     void registerBlobURLForSlice(const URL&, const URL& srcURL, long long start, long long end) override;
     void unregisterBlobURL(const URL&) override;
     bool isBlobRegistryImpl() const override { return true; }
index 78f39e8..423d643 100644 (file)
@@ -1,3 +1,23 @@
+2016-04-13  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB (Blob support): Support retrieving Blobs from IDB.
+        https://bugs.webkit.org/show_bug.cgi?id=156367
+
+        Reviewed by Alex Christensen.
+
+        * NetworkProcess/FileAPI/NetworkBlobRegistry.cpp:
+        (WebKit::NetworkBlobRegistry::registerBlobURLOptionallyFileBacked):
+        * NetworkProcess/FileAPI/NetworkBlobRegistry.h:
+        
+        * NetworkProcess/NetworkConnectionToWebProcess.cpp:
+        (WebKit::NetworkConnectionToWebProcess::registerBlobURLOptionallyFileBacked):
+        * NetworkProcess/NetworkConnectionToWebProcess.h:
+        * NetworkProcess/NetworkConnectionToWebProcess.messages.in:
+        
+        * WebProcess/FileAPI/BlobRegistryProxy.cpp:
+        (WebKit::BlobRegistryProxy::registerBlobURLOptionallyFileBacked):
+        * WebProcess/FileAPI/BlobRegistryProxy.h:
+
 2016-04-13  Chris Dumez  <cdumez@apple.com>
 
         We should not speculatively revalidate cached redirects
index 82dcd9f..26de817 100644 (file)
@@ -83,6 +83,17 @@ void NetworkBlobRegistry::registerBlobURL(NetworkConnectionToWebProcess* connect
     mapIterator->value.add(url);
 }
 
+void NetworkBlobRegistry::registerBlobURLOptionallyFileBacked(NetworkConnectionToWebProcess* connection, const URL& url, const URL& srcURL, const String& fileBackedPath)
+{
+    blobRegistry().registerBlobURLOptionallyFileBacked(url, srcURL, fileBackedPath);
+
+    ASSERT(!m_blobsForConnection.get(connection).contains(url));
+    BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(connection);
+    if (mapIterator == m_blobsForConnection.end())
+        mapIterator = m_blobsForConnection.add(connection, HashSet<URL>()).iterator;
+    mapIterator->value.add(url);
+}
+
 void NetworkBlobRegistry::registerBlobURLForSlice(NetworkConnectionToWebProcess* connection, const WebCore::URL& url, const WebCore::URL& srcURL, int64_t start, int64_t end)
 {
     // The connection may not be registered if NetworkProcess prevously crashed for any reason.
index 9f68407..9bfb2e6 100644 (file)
@@ -50,6 +50,7 @@ public:
     void registerFileBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&, const String& path, RefPtr<SandboxExtension>&&, const String& contentType);
     void registerBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&, Vector<WebCore::BlobPart>, const String& contentType);
     void registerBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&, const WebCore::URL& srcURL);
+    void registerBlobURLOptionallyFileBacked(NetworkConnectionToWebProcess*, const WebCore::URL&, const WebCore::URL& srcURL, const String& fileBackedPath);
     void registerBlobURLForSlice(NetworkConnectionToWebProcess*, const WebCore::URL&, const WebCore::URL& srcURL, int64_t start, int64_t end);
     void unregisterBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&);
     uint64_t blobSize(NetworkConnectionToWebProcess*, const WebCore::URL&);
index c001570..c817ba9 100644 (file)
@@ -271,6 +271,11 @@ void NetworkConnectionToWebProcess::registerBlobURLFromURL(const URL& url, const
     NetworkBlobRegistry::singleton().registerBlobURL(this, url, srcURL);
 }
 
+void NetworkConnectionToWebProcess::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath)
+{
+    NetworkBlobRegistry::singleton().registerBlobURLOptionallyFileBacked(this, url, srcURL, fileBackedPath);
+}
+
 void NetworkConnectionToWebProcess::registerBlobURLForSlice(const URL& url, const URL& srcURL, int64_t start, int64_t end)
 {
     NetworkBlobRegistry::singleton().registerBlobURLForSlice(this, url, srcURL, start, end);
index 1d11ba6..ce39f23 100644 (file)
@@ -91,6 +91,7 @@ private:
     void registerFileBlobURL(const WebCore::URL&, const String& path, const SandboxExtension::Handle&, const String& contentType);
     void registerBlobURL(const WebCore::URL&, Vector<WebCore::BlobPart>, const String& contentType);
     void registerBlobURLFromURL(const WebCore::URL&, const WebCore::URL& srcURL);
+    void registerBlobURLOptionallyFileBacked(const WebCore::URL&, const WebCore::URL& srcURL, const String& fileBackedPath);
     void registerBlobURLForSlice(const WebCore::URL&, const WebCore::URL& srcURL, int64_t start, int64_t end);
     void blobSize(const WebCore::URL&, uint64_t& resultSize);
     void unregisterBlobURL(const WebCore::URL&);
index 19e42f9..c705f3d 100644 (file)
@@ -43,6 +43,7 @@ messages -> NetworkConnectionToWebProcess LegacyReceiver {
     RegisterFileBlobURL(WebCore::URL url, String path, WebKit::SandboxExtension::Handle extensionHandle, String contentType)
     RegisterBlobURL(WebCore::URL url, Vector<WebCore::BlobPart> blobParts, String contentType)
     RegisterBlobURLFromURL(WebCore::URL url, WebCore::URL srcURL)
+    RegisterBlobURLOptionallyFileBacked(WebCore::URL url, WebCore::URL srcURL, String fileBackedPath)
     RegisterBlobURLForSlice(WebCore::URL url, WebCore::URL srcURL, int64_t start, int64_t end)
     UnregisterBlobURL(WebCore::URL url)
     BlobSize(WebCore::URL url) -> (uint64_t resultSize)
index 8269095..c97d495 100644 (file)
@@ -57,6 +57,11 @@ void BlobRegistryProxy::registerBlobURL(const URL& url, const URL& srcURL)
     WebProcess::singleton().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::RegisterBlobURLFromURL(url, srcURL), 0);
 }
 
+void BlobRegistryProxy::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath)
+{
+    WebProcess::singleton().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::RegisterBlobURLOptionallyFileBacked(url, srcURL, fileBackedPath), 0);
+}
+
 void BlobRegistryProxy::unregisterBlobURL(const URL& url)
 {
     WebProcess::singleton().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::UnregisterBlobURL(url), 0);
index c7b3377..f39d6bd 100644 (file)
@@ -35,6 +35,7 @@ public:
     void registerFileBlobURL(const WebCore::URL&, RefPtr<WebCore::BlobDataFileReference>&&, const String& contentType) override;
     void registerBlobURL(const WebCore::URL&, Vector<WebCore::BlobPart>, const String& contentType) override;
     void registerBlobURL(const WebCore::URL&, const WebCore::URL& srcURL) override;
+    void registerBlobURLOptionallyFileBacked(const WebCore::URL&, const WebCore::URL& srcURL, const String& fileBackedPath) override;
     void unregisterBlobURL(const WebCore::URL&) override;
     void registerBlobURLForSlice(const WebCore::URL&, const WebCore::URL& srcURL, long long start, long long end) override;
     unsigned long long blobSize(const WebCore::URL&) override;