// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/child/indexed_db/indexed_db_dispatcher.h" #include #include "base/format_macros.h" #include "base/lazy_instance.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_local.h" #include "content/child/indexed_db/indexed_db_key_builders.h" #include "content/child/indexed_db/webidbcursor_impl.h" #include "content/child/indexed_db/webidbdatabase_impl.h" #include "content/child/thread_safe_sender.h" #include "content/common/indexed_db/indexed_db_constants.h" #include "content/common/indexed_db/indexed_db_messages.h" #include "ipc/ipc_channel.h" #include "third_party/WebKit/public/platform/WebIDBDatabaseCallbacks.h" #include "third_party/WebKit/public/platform/WebIDBDatabaseError.h" #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h" using blink::WebBlobInfo; using blink::WebData; using blink::WebIDBCallbacks; using blink::WebIDBCursor; using blink::WebIDBDatabase; using blink::WebIDBDatabaseCallbacks; using blink::WebIDBDatabaseError; using blink::WebIDBKey; using blink::WebIDBMetadata; using blink::WebString; using blink::WebVector; using base::ThreadLocalPointer; namespace content { static base::LazyInstance >::Leaky g_idb_dispatcher_tls = LAZY_INSTANCE_INITIALIZER; namespace { IndexedDBDispatcher* const kHasBeenDeleted = reinterpret_cast(0x1); } // unnamed namespace const size_t kMaxIDBMessageOverhead = 1024 * 1024; // 1MB; arbitrarily chosen. const size_t kMaxIDBValueSizeInBytes = IPC::Channel::kMaximumMessageSize - kMaxIDBMessageOverhead; IndexedDBDispatcher::IndexedDBDispatcher(ThreadSafeSender* thread_safe_sender) : thread_safe_sender_(thread_safe_sender) { g_idb_dispatcher_tls.Pointer()->Set(this); } IndexedDBDispatcher::~IndexedDBDispatcher() { // Clear any pending callbacks - which may result in dispatch requests - // before marking the dispatcher as deleted. pending_callbacks_.Clear(); pending_database_callbacks_.Clear(); DCHECK(pending_callbacks_.IsEmpty()); DCHECK(pending_database_callbacks_.IsEmpty()); g_idb_dispatcher_tls.Pointer()->Set(kHasBeenDeleted); } IndexedDBDispatcher* IndexedDBDispatcher::ThreadSpecificInstance( ThreadSafeSender* thread_safe_sender) { if (g_idb_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) { NOTREACHED() << "Re-instantiating TLS IndexedDBDispatcher."; g_idb_dispatcher_tls.Pointer()->Set(NULL); } if (g_idb_dispatcher_tls.Pointer()->Get()) return g_idb_dispatcher_tls.Pointer()->Get(); IndexedDBDispatcher* dispatcher = new IndexedDBDispatcher(thread_safe_sender); if (WorkerTaskRunner::Instance()->CurrentWorkerId()) WorkerTaskRunner::Instance()->AddStopObserver(dispatcher); return dispatcher; } void IndexedDBDispatcher::OnWorkerRunLoopStopped() { delete this; } WebIDBMetadata IndexedDBDispatcher::ConvertMetadata( const IndexedDBDatabaseMetadata& idb_metadata) { WebIDBMetadata web_metadata; web_metadata.id = idb_metadata.id; web_metadata.name = idb_metadata.name; web_metadata.version = idb_metadata.version; web_metadata.intVersion = idb_metadata.int_version; web_metadata.maxObjectStoreId = idb_metadata.max_object_store_id; web_metadata.objectStores = WebVector(idb_metadata.object_stores.size()); for (size_t i = 0; i < idb_metadata.object_stores.size(); ++i) { const IndexedDBObjectStoreMetadata& idb_store_metadata = idb_metadata.object_stores[i]; WebIDBMetadata::ObjectStore& web_store_metadata = web_metadata.objectStores[i]; web_store_metadata.id = idb_store_metadata.id; web_store_metadata.name = idb_store_metadata.name; web_store_metadata.keyPath = WebIDBKeyPathBuilder::Build(idb_store_metadata.keyPath); web_store_metadata.autoIncrement = idb_store_metadata.autoIncrement; web_store_metadata.maxIndexId = idb_store_metadata.max_index_id; web_store_metadata.indexes = WebVector(idb_store_metadata.indexes.size()); for (size_t j = 0; j < idb_store_metadata.indexes.size(); ++j) { const IndexedDBIndexMetadata& idb_index_metadata = idb_store_metadata.indexes[j]; WebIDBMetadata::Index& web_index_metadata = web_store_metadata.indexes[j]; web_index_metadata.id = idb_index_metadata.id; web_index_metadata.name = idb_index_metadata.name; web_index_metadata.keyPath = WebIDBKeyPathBuilder::Build(idb_index_metadata.keyPath); web_index_metadata.unique = idb_index_metadata.unique; web_index_metadata.multiEntry = idb_index_metadata.multiEntry; } } return web_metadata; } void IndexedDBDispatcher::OnMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(IndexedDBDispatcher, msg) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBCursor, OnSuccessOpenCursor) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorAdvance, OnSuccessCursorContinue) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorContinue, OnSuccessCursorContinue) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorPrefetch, OnSuccessCursorPrefetch) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBDatabase, OnSuccessIDBDatabase) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIndexedDBKey, OnSuccessIndexedDBKey) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessStringList, OnSuccessStringList) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessValue, OnSuccessValue) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessValueWithKey, OnSuccessValueWithKey) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessInteger, OnSuccessInteger) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessUndefined, OnSuccessUndefined) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksError, OnError) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksIntBlocked, OnIntBlocked) IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksUpgradeNeeded, OnUpgradeNeeded) IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksForcedClose, OnForcedClose) IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksIntVersionChange, OnIntVersionChange) IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksAbort, OnAbort) IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksComplete, OnComplete) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() // If a message gets here, IndexedDBMessageFilter already determined that it // is an IndexedDB message. DCHECK(handled) << "Didn't handle a message defined at line " << IPC_MESSAGE_ID_LINE(msg.type()); } bool IndexedDBDispatcher::Send(IPC::Message* msg) { return thread_safe_sender_->Send(msg); } void IndexedDBDispatcher::RequestIDBCursorAdvance( unsigned long count, WebIDBCallbacks* callbacks_ptr, int32 ipc_cursor_id, int64 transaction_id) { // Reset all cursor prefetch caches except for this cursor. ResetCursorPrefetchCaches(transaction_id, ipc_cursor_id); scoped_ptr callbacks(callbacks_ptr); int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); Send(new IndexedDBHostMsg_CursorAdvance( ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, count)); } void IndexedDBDispatcher::RequestIDBCursorContinue( const IndexedDBKey& key, const IndexedDBKey& primary_key, WebIDBCallbacks* callbacks_ptr, int32 ipc_cursor_id, int64 transaction_id) { // Reset all cursor prefetch caches except for this cursor. ResetCursorPrefetchCaches(transaction_id, ipc_cursor_id); scoped_ptr callbacks(callbacks_ptr); int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); Send(new IndexedDBHostMsg_CursorContinue( ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, key, primary_key)); } void IndexedDBDispatcher::RequestIDBCursorPrefetch( int n, WebIDBCallbacks* callbacks_ptr, int32 ipc_cursor_id) { scoped_ptr callbacks(callbacks_ptr); int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); Send(new IndexedDBHostMsg_CursorPrefetch( ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, n)); } void IndexedDBDispatcher::RequestIDBCursorPrefetchReset(int used_prefetches, int unused_prefetches, int32 ipc_cursor_id) { Send(new IndexedDBHostMsg_CursorPrefetchReset( ipc_cursor_id, used_prefetches, unused_prefetches)); } void IndexedDBDispatcher::RequestIDBFactoryOpen( const base::string16& name, int64 version, int64 transaction_id, WebIDBCallbacks* callbacks_ptr, WebIDBDatabaseCallbacks* database_callbacks_ptr, const std::string& database_identifier) { scoped_ptr callbacks(callbacks_ptr); scoped_ptr database_callbacks( database_callbacks_ptr); IndexedDBHostMsg_FactoryOpen_Params params; params.ipc_thread_id = CurrentWorkerId(); params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); params.ipc_database_callbacks_id = pending_database_callbacks_.Add(database_callbacks.release()); params.database_identifier = database_identifier; params.name = name; params.transaction_id = transaction_id; params.version = version; Send(new IndexedDBHostMsg_FactoryOpen(params)); } void IndexedDBDispatcher::RequestIDBFactoryGetDatabaseNames( WebIDBCallbacks* callbacks_ptr, const std::string& database_identifier) { scoped_ptr callbacks(callbacks_ptr); IndexedDBHostMsg_FactoryGetDatabaseNames_Params params; params.ipc_thread_id = CurrentWorkerId(); params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); params.database_identifier = database_identifier; Send(new IndexedDBHostMsg_FactoryGetDatabaseNames(params)); } void IndexedDBDispatcher::RequestIDBFactoryDeleteDatabase( const base::string16& name, WebIDBCallbacks* callbacks_ptr, const std::string& database_identifier) { scoped_ptr callbacks(callbacks_ptr); IndexedDBHostMsg_FactoryDeleteDatabase_Params params; params.ipc_thread_id = CurrentWorkerId(); params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); params.database_identifier = database_identifier; params.name = name; Send(new IndexedDBHostMsg_FactoryDeleteDatabase(params)); } void IndexedDBDispatcher::RequestIDBDatabaseClose( int32 ipc_database_id, int32 ipc_database_callbacks_id) { Send(new IndexedDBHostMsg_DatabaseClose(ipc_database_id)); // There won't be pending database callbacks if the transaction was aborted in // the initial upgradeneeded event handler. if (pending_database_callbacks_.Lookup(ipc_database_callbacks_id)) pending_database_callbacks_.Remove(ipc_database_callbacks_id); } void IndexedDBDispatcher::NotifyIDBDatabaseVersionChangeIgnored( int32 ipc_database_id) { Send(new IndexedDBHostMsg_DatabaseVersionChangeIgnored(ipc_database_id)); } void IndexedDBDispatcher::RequestIDBDatabaseCreateTransaction( int32 ipc_database_id, int64 transaction_id, WebIDBDatabaseCallbacks* database_callbacks_ptr, WebVector object_store_ids, blink::WebIDBTransactionMode mode) { scoped_ptr database_callbacks( database_callbacks_ptr); IndexedDBHostMsg_DatabaseCreateTransaction_Params params; params.ipc_thread_id = CurrentWorkerId(); params.ipc_database_id = ipc_database_id; params.transaction_id = transaction_id; params.ipc_database_callbacks_id = pending_database_callbacks_.Add(database_callbacks.release()); params.object_store_ids .assign(object_store_ids.data(), object_store_ids.data() + object_store_ids.size()); params.mode = mode; Send(new IndexedDBHostMsg_DatabaseCreateTransaction(params)); } void IndexedDBDispatcher::RequestIDBDatabaseGet( int32 ipc_database_id, int64 transaction_id, int64 object_store_id, int64 index_id, const IndexedDBKeyRange& key_range, bool key_only, WebIDBCallbacks* callbacks) { ResetCursorPrefetchCaches(transaction_id, kAllCursors); IndexedDBHostMsg_DatabaseGet_Params params; init_params(¶ms, callbacks); params.ipc_database_id = ipc_database_id; params.transaction_id = transaction_id; params.object_store_id = object_store_id; params.index_id = index_id; params.key_range = key_range; params.key_only = key_only; Send(new IndexedDBHostMsg_DatabaseGet(params)); } void IndexedDBDispatcher::RequestIDBDatabasePut( int32 ipc_database_id, int64 transaction_id, int64 object_store_id, const WebData& value, const blink::WebVector& web_blob_info, const IndexedDBKey& key, blink::WebIDBPutMode put_mode, WebIDBCallbacks* callbacks, const WebVector& index_ids, const WebVector >& index_keys) { if (value.size() + key.size_estimate() > kMaxIDBValueSizeInBytes) { callbacks->onError(WebIDBDatabaseError( blink::WebIDBDatabaseExceptionUnknownError, WebString::fromUTF8(base::StringPrintf( "The serialized value is too large" " (size=%" PRIuS " bytes, max=%" PRIuS " bytes).", value.size(), kMaxIDBValueSizeInBytes).c_str()))); return; } ResetCursorPrefetchCaches(transaction_id, kAllCursors); IndexedDBHostMsg_DatabasePut_Params params; init_params(¶ms, callbacks); params.ipc_database_id = ipc_database_id; params.transaction_id = transaction_id; params.object_store_id = object_store_id; params.value.assign(value.data(), value.data() + value.size()); params.key = key; params.put_mode = put_mode; DCHECK_EQ(index_ids.size(), index_keys.size()); params.index_keys.resize(index_ids.size()); for (size_t i = 0, len = index_ids.size(); i < len; ++i) { params.index_keys[i].first = index_ids[i]; params.index_keys[i].second.resize(index_keys[i].size()); for (size_t j = 0; j < index_keys[i].size(); ++j) { params.index_keys[i].second[j] = IndexedDBKey(IndexedDBKeyBuilder::Build(index_keys[i][j])); } } params.blob_or_file_info.resize(web_blob_info.size()); for (size_t i = 0; i < web_blob_info.size(); ++i) { const WebBlobInfo& info = web_blob_info[i]; IndexedDBMsg_BlobOrFileInfo& blob_or_file_info = params.blob_or_file_info[i]; blob_or_file_info.is_file = info.isFile(); if (info.isFile()) { blob_or_file_info.file_path = info.filePath(); blob_or_file_info.file_name = info.fileName(); blob_or_file_info.last_modified = info.lastModified(); } blob_or_file_info.size = info.size(); blob_or_file_info.uuid = info.uuid().latin1(); DCHECK(blob_or_file_info.uuid.size()); blob_or_file_info.mime_type = info.type(); } Send(new IndexedDBHostMsg_DatabasePut(params)); } void IndexedDBDispatcher::RequestIDBDatabaseOpenCursor( int32 ipc_database_id, int64 transaction_id, int64 object_store_id, int64 index_id, const IndexedDBKeyRange& key_range, blink::WebIDBCursorDirection direction, bool key_only, blink::WebIDBTaskType task_type, WebIDBCallbacks* callbacks) { ResetCursorPrefetchCaches(transaction_id, kAllCursors); IndexedDBHostMsg_DatabaseOpenCursor_Params params; init_params(¶ms, callbacks); params.ipc_database_id = ipc_database_id; params.transaction_id = transaction_id; params.object_store_id = object_store_id; params.index_id = index_id; params.key_range = key_range; params.direction = direction; params.key_only = key_only; params.task_type = task_type; Send(new IndexedDBHostMsg_DatabaseOpenCursor(params)); DCHECK(cursor_transaction_ids_.find(params.ipc_callbacks_id) == cursor_transaction_ids_.end()); cursor_transaction_ids_[params.ipc_callbacks_id] = transaction_id; } void IndexedDBDispatcher::RequestIDBDatabaseCount( int32 ipc_database_id, int64 transaction_id, int64 object_store_id, int64 index_id, const IndexedDBKeyRange& key_range, WebIDBCallbacks* callbacks) { ResetCursorPrefetchCaches(transaction_id, kAllCursors); IndexedDBHostMsg_DatabaseCount_Params params; init_params(¶ms, callbacks); params.ipc_database_id = ipc_database_id; params.transaction_id = transaction_id; params.object_store_id = object_store_id; params.index_id = index_id; params.key_range = key_range; Send(new IndexedDBHostMsg_DatabaseCount(params)); } void IndexedDBDispatcher::RequestIDBDatabaseDeleteRange( int32 ipc_database_id, int64 transaction_id, int64 object_store_id, const IndexedDBKeyRange& key_range, WebIDBCallbacks* callbacks) { ResetCursorPrefetchCaches(transaction_id, kAllCursors); IndexedDBHostMsg_DatabaseDeleteRange_Params params; init_params(¶ms, callbacks); params.ipc_database_id = ipc_database_id; params.transaction_id = transaction_id; params.object_store_id = object_store_id; params.key_range = key_range; Send(new IndexedDBHostMsg_DatabaseDeleteRange(params)); } void IndexedDBDispatcher::RequestIDBDatabaseClear( int32 ipc_database_id, int64 transaction_id, int64 object_store_id, WebIDBCallbacks* callbacks_ptr) { ResetCursorPrefetchCaches(transaction_id, kAllCursors); scoped_ptr callbacks(callbacks_ptr); int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); Send(new IndexedDBHostMsg_DatabaseClear(CurrentWorkerId(), ipc_callbacks_id, ipc_database_id, transaction_id, object_store_id)); } void IndexedDBDispatcher::CursorDestroyed(int32 ipc_cursor_id) { cursors_.erase(ipc_cursor_id); } void IndexedDBDispatcher::DatabaseDestroyed(int32 ipc_database_id) { DCHECK_EQ(databases_.count(ipc_database_id), 1u); databases_.erase(ipc_database_id); } void IndexedDBDispatcher::OnSuccessIDBDatabase( int32 ipc_thread_id, int32 ipc_callbacks_id, int32 ipc_database_callbacks_id, int32 ipc_object_id, const IndexedDBDatabaseMetadata& idb_metadata) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); if (!callbacks) return; WebIDBMetadata metadata(ConvertMetadata(idb_metadata)); // If an upgrade was performed, count will be non-zero. WebIDBDatabase* database = NULL; // Back-end will send kNoDatabase if it was already sent in OnUpgradeNeeded. // May already be deleted and removed from the table, but do not recreate.. if (ipc_object_id != kNoDatabase) { DCHECK(!databases_.count(ipc_object_id)); database = databases_[ipc_object_id] = new WebIDBDatabaseImpl( ipc_object_id, ipc_database_callbacks_id, thread_safe_sender_.get()); } callbacks->onSuccess(database, metadata); pending_callbacks_.Remove(ipc_callbacks_id); } void IndexedDBDispatcher::OnSuccessIndexedDBKey(int32 ipc_thread_id, int32 ipc_callbacks_id, const IndexedDBKey& key) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); if (!callbacks) return; callbacks->onSuccess(WebIDBKeyBuilder::Build(key)); pending_callbacks_.Remove(ipc_callbacks_id); } void IndexedDBDispatcher::OnSuccessStringList( int32 ipc_thread_id, int32 ipc_callbacks_id, const std::vector& value) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); if (!callbacks) return; callbacks->onSuccess(WebVector(value)); pending_callbacks_.Remove(ipc_callbacks_id); } static void PrepareWebValueAndBlobInfo( const std::string& value, const std::vector& blob_info, WebData* web_value, blink::WebVector* web_blob_info) { if (value.empty()) return; web_value->assign(&*value.begin(), value.size()); blink::WebVector local_blob_info(blob_info.size()); for (size_t i = 0; i < blob_info.size(); ++i) { const IndexedDBMsg_BlobOrFileInfo& info = blob_info[i]; if (info.is_file) { local_blob_info[i] = WebBlobInfo(WebString::fromUTF8(info.uuid.c_str()), info.file_path, info.file_name, info.mime_type, info.last_modified, info.size); } else { local_blob_info[i] = WebBlobInfo( WebString::fromUTF8(info.uuid.c_str()), info.mime_type, info.size); } } web_blob_info->swap(local_blob_info); } void IndexedDBDispatcher::OnSuccessValue( const IndexedDBMsg_CallbacksSuccessValue_Params& params) { DCHECK_EQ(params.ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(params.ipc_callbacks_id); if (!callbacks) return; WebData web_value; WebVector web_blob_info; PrepareWebValueAndBlobInfo( params.value, params.blob_or_file_info, &web_value, &web_blob_info); callbacks->onSuccess(web_value, web_blob_info); pending_callbacks_.Remove(params.ipc_callbacks_id); cursor_transaction_ids_.erase(params.ipc_callbacks_id); } void IndexedDBDispatcher::OnSuccessValueWithKey( const IndexedDBMsg_CallbacksSuccessValueWithKey_Params& params) { DCHECK_EQ(params.ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(params.ipc_callbacks_id); if (!callbacks) return; WebData web_value; WebVector web_blob_info; PrepareWebValueAndBlobInfo( params.value, params.blob_or_file_info, &web_value, &web_blob_info); callbacks->onSuccess(web_value, web_blob_info, WebIDBKeyBuilder::Build(params.primary_key), WebIDBKeyPathBuilder::Build(params.key_path)); pending_callbacks_.Remove(params.ipc_callbacks_id); } void IndexedDBDispatcher::OnSuccessInteger(int32 ipc_thread_id, int32 ipc_callbacks_id, int64 value) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); if (!callbacks) return; callbacks->onSuccess(value); pending_callbacks_.Remove(ipc_callbacks_id); } void IndexedDBDispatcher::OnSuccessUndefined(int32 ipc_thread_id, int32 ipc_callbacks_id) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); if (!callbacks) return; callbacks->onSuccess(); pending_callbacks_.Remove(ipc_callbacks_id); } void IndexedDBDispatcher::OnSuccessOpenCursor( const IndexedDBMsg_CallbacksSuccessIDBCursor_Params& p) { DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId()); int32 ipc_callbacks_id = p.ipc_callbacks_id; int32 ipc_object_id = p.ipc_cursor_id; const IndexedDBKey& key = p.key; const IndexedDBKey& primary_key = p.primary_key; WebData web_value; WebVector web_blob_info; PrepareWebValueAndBlobInfo( p.value, p.blob_or_file_info, &web_value, &web_blob_info); DCHECK(cursor_transaction_ids_.find(ipc_callbacks_id) != cursor_transaction_ids_.end()); int64 transaction_id = cursor_transaction_ids_[ipc_callbacks_id]; cursor_transaction_ids_.erase(ipc_callbacks_id); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); if (!callbacks) return; WebIDBCursorImpl* cursor = new WebIDBCursorImpl( ipc_object_id, transaction_id, thread_safe_sender_.get()); cursors_[ipc_object_id] = cursor; callbacks->onSuccess(cursor, WebIDBKeyBuilder::Build(key), WebIDBKeyBuilder::Build(primary_key), web_value, web_blob_info); pending_callbacks_.Remove(ipc_callbacks_id); } void IndexedDBDispatcher::OnSuccessCursorContinue( const IndexedDBMsg_CallbacksSuccessCursorContinue_Params& p) { DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId()); int32 ipc_callbacks_id = p.ipc_callbacks_id; int32 ipc_cursor_id = p.ipc_cursor_id; const IndexedDBKey& key = p.key; const IndexedDBKey& primary_key = p.primary_key; const std::string& value = p.value; if (cursors_.find(ipc_cursor_id) == cursors_.end()) return; WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); if (!callbacks) return; WebData web_value; WebVector web_blob_info; PrepareWebValueAndBlobInfo( value, p.blob_or_file_info, &web_value, &web_blob_info); callbacks->onSuccess(WebIDBKeyBuilder::Build(key), WebIDBKeyBuilder::Build(primary_key), web_value, web_blob_info); pending_callbacks_.Remove(ipc_callbacks_id); } void IndexedDBDispatcher::OnSuccessCursorPrefetch( const IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params& p) { DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId()); int32 ipc_callbacks_id = p.ipc_callbacks_id; int32 ipc_cursor_id = p.ipc_cursor_id; const std::vector& keys = p.keys; const std::vector& primary_keys = p.primary_keys; std::vector values(p.values.size()); DCHECK_EQ(p.values.size(), p.blob_or_file_infos.size()); std::vector > blob_infos(p.blob_or_file_infos.size()); for (size_t i = 0; i < p.values.size(); ++i) { PrepareWebValueAndBlobInfo( p.values[i], p.blob_or_file_infos[i], &values[i], &blob_infos[i]); } std::map::const_iterator cur_iter = cursors_.find(ipc_cursor_id); if (cur_iter == cursors_.end()) return; cur_iter->second->SetPrefetchData(keys, primary_keys, values, blob_infos); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); DCHECK(callbacks); cur_iter->second->CachedContinue(callbacks); pending_callbacks_.Remove(ipc_callbacks_id); } void IndexedDBDispatcher::OnIntBlocked(int32 ipc_thread_id, int32 ipc_callbacks_id, int64 existing_version) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); DCHECK(callbacks); callbacks->onBlocked(existing_version); } void IndexedDBDispatcher::OnUpgradeNeeded( const IndexedDBMsg_CallbacksUpgradeNeeded_Params& p) { DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(p.ipc_callbacks_id); DCHECK(callbacks); WebIDBMetadata metadata(ConvertMetadata(p.idb_metadata)); DCHECK(!databases_.count(p.ipc_database_id)); databases_[p.ipc_database_id] = new WebIDBDatabaseImpl(p.ipc_database_id, p.ipc_database_callbacks_id, thread_safe_sender_.get()); callbacks->onUpgradeNeeded( p.old_version, databases_[p.ipc_database_id], metadata, static_cast(p.data_loss), WebString::fromUTF8(p.data_loss_message)); } void IndexedDBDispatcher::OnError(int32 ipc_thread_id, int32 ipc_callbacks_id, int code, const base::string16& message) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); if (!callbacks) return; if (message.empty()) callbacks->onError(WebIDBDatabaseError(code)); else callbacks->onError(WebIDBDatabaseError(code, message)); pending_callbacks_.Remove(ipc_callbacks_id); cursor_transaction_ids_.erase(ipc_callbacks_id); } void IndexedDBDispatcher::OnAbort(int32 ipc_thread_id, int32 ipc_database_callbacks_id, int64 transaction_id, int code, const base::string16& message) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBDatabaseCallbacks* callbacks = pending_database_callbacks_.Lookup(ipc_database_callbacks_id); if (!callbacks) return; if (message.empty()) callbacks->onAbort(transaction_id, WebIDBDatabaseError(code)); else callbacks->onAbort(transaction_id, WebIDBDatabaseError(code, message)); } void IndexedDBDispatcher::OnComplete(int32 ipc_thread_id, int32 ipc_database_callbacks_id, int64 transaction_id) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBDatabaseCallbacks* callbacks = pending_database_callbacks_.Lookup(ipc_database_callbacks_id); if (!callbacks) return; callbacks->onComplete(transaction_id); } void IndexedDBDispatcher::OnForcedClose(int32 ipc_thread_id, int32 ipc_database_callbacks_id) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBDatabaseCallbacks* callbacks = pending_database_callbacks_.Lookup(ipc_database_callbacks_id); if (!callbacks) return; callbacks->onForcedClose(); } void IndexedDBDispatcher::OnIntVersionChange(int32 ipc_thread_id, int32 ipc_database_callbacks_id, int64 old_version, int64 new_version) { DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); WebIDBDatabaseCallbacks* callbacks = pending_database_callbacks_.Lookup(ipc_database_callbacks_id); // callbacks would be NULL if a versionchange event is received after close // has been called. if (!callbacks) return; callbacks->onVersionChange(old_version, new_version); } void IndexedDBDispatcher::ResetCursorPrefetchCaches( int64 transaction_id, int32 ipc_exception_cursor_id) { typedef std::map::iterator Iterator; for (Iterator i = cursors_.begin(); i != cursors_.end(); ++i) { if (i->first == ipc_exception_cursor_id || i->second->transaction_id() != transaction_id) continue; i->second->ResetPrefetchCache(); } } } // namespace content