// Copyright (c) 2012 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/browser/in_process_webkit/indexed_db_dispatcher_host.h" #include #include "base/bind.h" #include "base/command_line.h" #include "base/process.h" #include "base/process_util.h" #include "base/utf_string_conversions.h" #include "content/browser/in_process_webkit/indexed_db_callbacks.h" #include "content/browser/in_process_webkit/indexed_db_database_callbacks.h" #include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/browser/renderer_host/render_message_filter.h" #include "content/common/indexed_db/indexed_db_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/user_metrics.h" #include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" #include "googleurl/src/gurl.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebData.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBCursor.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBDatabase.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBDatabaseCallbacks.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBDatabaseError.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBDatabaseException.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBFactory.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBMetadata.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebVector.h" #include "webkit/base/file_path_string_conversions.h" #include "webkit/database/database_util.h" using webkit_database::DatabaseUtil; using WebKit::WebData; using WebKit::WebIDBCallbacks; using WebKit::WebIDBCursor; using WebKit::WebIDBDatabase; using WebKit::WebIDBDatabaseError; using WebKit::WebIDBIndex; using WebKit::WebIDBKey; using WebKit::WebIDBMetadata; using WebKit::WebIDBObjectStore; using WebKit::WebString; using WebKit::WebVector; namespace content { namespace { template void DeleteOnWebKitThread(T* obj) { if (!BrowserThread::DeleteSoon(BrowserThread::WEBKIT_DEPRECATED, FROM_HERE, obj)) delete obj; } } IndexedDBDispatcherHost::IndexedDBDispatcherHost( int ipc_process_id, IndexedDBContextImpl* indexed_db_context) : indexed_db_context_(indexed_db_context), database_dispatcher_host_(new DatabaseDispatcherHost(this)), cursor_dispatcher_host_(new CursorDispatcherHost(this)), ipc_process_id_(ipc_process_id) { DCHECK(indexed_db_context_.get()); } IndexedDBDispatcherHost::~IndexedDBDispatcherHost() { } void IndexedDBDispatcherHost::OnChannelClosing() { BrowserMessageFilter::OnChannelClosing(); bool success = BrowserThread::PostTask( BrowserThread::WEBKIT_DEPRECATED, FROM_HERE, base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this)); if (!success) ResetDispatcherHosts(); } void IndexedDBDispatcherHost::ResetDispatcherHosts() { // It is important that the various *_dispatcher_host_ members are reset // on the WebKit thread, since there might be incoming messages on that // thread, and we must not reset the dispatcher hosts until after those // messages are processed. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED) || CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)); // Note that we explicitly separate CloseAll() from destruction of the // DatabaseDispatcherHost, since CloseAll() can invoke callbacks which need to // be dispatched through database_dispatcher_host_. database_dispatcher_host_->CloseAll(); database_dispatcher_host_.reset(); cursor_dispatcher_host_.reset(); } void IndexedDBDispatcherHost::OverrideThreadForMessage( const IPC::Message& message, BrowserThread::ID* thread) { if (IPC_MESSAGE_CLASS(message) == IndexedDBMsgStart) *thread = BrowserThread::WEBKIT_DEPRECATED; } bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message, bool* message_was_ok) { if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart) return false; DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); bool handled = database_dispatcher_host_->OnMessageReceived(message, message_was_ok) || cursor_dispatcher_host_->OnMessageReceived(message, message_was_ok); if (!handled) { handled = true; IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost, message, *message_was_ok) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames, OnIDBFactoryGetDatabaseNames) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase, OnIDBFactoryDeleteDatabase) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() } return handled; } int32 IndexedDBDispatcherHost::Add(WebIDBCursor* idb_cursor) { if (!cursor_dispatcher_host_) { delete idb_cursor; return 0; } return cursor_dispatcher_host_->map_.Add(idb_cursor); } int32 IndexedDBDispatcherHost::Add(WebIDBDatabase* idb_database, int32 ipc_thread_id, const GURL& origin_url) { if (!database_dispatcher_host_) { delete idb_database; return 0; } int32 ipc_database_id = database_dispatcher_host_->map_.Add(idb_database); Context()->ConnectionOpened(origin_url, idb_database); database_dispatcher_host_->database_url_map_[ipc_database_id] = origin_url; return ipc_database_id; } void IndexedDBDispatcherHost::RegisterTransactionId( int64 host_transaction_id, const GURL& url) { if (!database_dispatcher_host_) return; database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url; } int64 IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id) { // Inject the renderer process id into the transaction id, to // uniquely identify this transaction, and effectively bind it to // the renderer that initiated it. The lower 32 bits of // transaction_id are guaranteed to be unique within that renderer. base::ProcessId pid = base::GetProcId(peer_handle()); DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits"; COMPILE_ASSERT(sizeof(base::ProcessId) <= sizeof(int32), Process_ID_must_fit_in_32_bits); return transaction_id | (static_cast(pid) << 32); } int64 IndexedDBDispatcherHost::RendererTransactionId( int64 host_transaction_id) { DCHECK(host_transaction_id >> 32 == base::GetProcId(peer_handle())) << "Invalid renderer target for transaction id"; return host_transaction_id & 0xffffffff; } WebIDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); return cursor_dispatcher_host_->map_.Lookup(ipc_cursor_id); } IndexedDBDatabaseMetadata IndexedDBDispatcherHost::ConvertMetadata( const WebIDBMetadata& web_metadata) { IndexedDBDatabaseMetadata metadata; metadata.id = web_metadata.id; metadata.name = web_metadata.name; metadata.version = web_metadata.version; metadata.int_version = web_metadata.intVersion; metadata.max_object_store_id = web_metadata.maxObjectStoreId; for (size_t i = 0; i < web_metadata.objectStores.size(); ++i) { const WebIDBMetadata::ObjectStore& web_store_metadata = web_metadata.objectStores[i]; IndexedDBObjectStoreMetadata idb_store_metadata; idb_store_metadata.id = web_store_metadata.id; idb_store_metadata.name = web_store_metadata.name; idb_store_metadata.keyPath = IndexedDBKeyPath(web_store_metadata.keyPath); idb_store_metadata.autoIncrement = web_store_metadata.autoIncrement; idb_store_metadata.max_index_id = web_store_metadata.maxIndexId; for (size_t j = 0; j < web_store_metadata.indexes.size(); ++j) { const WebIDBMetadata::Index& web_index_metadata = web_store_metadata.indexes[j]; IndexedDBIndexMetadata idb_index_metadata; idb_index_metadata.id = web_index_metadata.id; idb_index_metadata.name = web_index_metadata.name; idb_index_metadata.keyPath = IndexedDBKeyPath(web_index_metadata.keyPath); idb_index_metadata.unique = web_index_metadata.unique; idb_index_metadata.multiEntry = web_index_metadata.multiEntry; idb_store_metadata.indexes.push_back(idb_index_metadata); } metadata.object_stores.push_back(idb_store_metadata); } return metadata; } void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames( const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); base::FilePath indexed_db_path = indexed_db_context_->data_path(); Context()->GetIDBFactory()->getDatabaseNames( new IndexedDBCallbacks >(this, params.ipc_thread_id, params.ipc_callbacks_id), params.database_identifier, webkit_base::FilePathToWebString(indexed_db_path)); } void IndexedDBDispatcherHost::OnIDBFactoryOpen( const IndexedDBHostMsg_FactoryOpen_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); base::FilePath indexed_db_path = indexed_db_context_->data_path(); GURL origin_url = DatabaseUtil::GetOriginFromIdentifier(params.database_identifier); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); int64 host_transaction_id = HostTransactionId(params.transaction_id); // TODO(dgrogan): Don't let a non-existing database be opened (and therefore // created) if this origin is already over quota. Context()->GetIDBFactory()->open( params.name, params.version, host_transaction_id, new IndexedDBCallbacksDatabase(this, params.ipc_thread_id, params.ipc_callbacks_id, params.ipc_database_callbacks_id, host_transaction_id, origin_url), new IndexedDBDatabaseCallbacks(this, params.ipc_thread_id, params.ipc_database_callbacks_id), params.database_identifier, webkit_base::FilePathToWebString(indexed_db_path)); } void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase( const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) { base::FilePath indexed_db_path = indexed_db_context_->data_path(); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); Context()->GetIDBFactory()->deleteDatabase( params.name, new IndexedDBCallbacks(this, params.ipc_thread_id, params.ipc_callbacks_id), params.database_identifier, webkit_base::FilePathToWebString(indexed_db_path)); } void IndexedDBDispatcherHost::FinishTransaction( int64 host_transaction_id, bool committed) { TransactionIDToURLMap& transaction_url_map = database_dispatcher_host_->transaction_url_map_; TransactionIDToSizeMap& transaction_size_map = database_dispatcher_host_->transaction_size_map_; TransactionIDToDatabaseIDMap& transaction_database_map = database_dispatcher_host_->transaction_database_map_; if (committed) Context()->TransactionComplete(transaction_url_map[host_transaction_id]); // It's unclear if std::map::erase(key) has defined behavior if the // key is not found. // TODO(alecflett): Remove if it is proven that it is safe. if (transaction_url_map.find(host_transaction_id) != transaction_url_map.end()) transaction_url_map.erase(host_transaction_id); if (transaction_size_map.find(host_transaction_id) != transaction_size_map.end()) transaction_size_map.erase(host_transaction_id); if (transaction_database_map.find(host_transaction_id) != transaction_database_map.end()) transaction_database_map.erase(host_transaction_id); } ////////////////////////////////////////////////////////////////////// // Helper templates. // template ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess( IDMap* map, int32 ipc_return_object_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); ObjectType* return_object = map->Lookup(ipc_return_object_id); if (!return_object) { NOTREACHED() << "Uh oh, couldn't find object with id " << ipc_return_object_id; RecordAction(UserMetricsAction("BadMessageTerminate_IDBMF")); BadMessageReceived(); } return return_object; } template void IndexedDBDispatcherHost::DestroyObject( IDMap* map, int32 ipc_object_id) { GetOrTerminateProcess(map, ipc_object_id); map->Remove(ipc_object_id); } ////////////////////////////////////////////////////////////////////// // IndexedDBDispatcherHost::DatabaseDispatcherHost // IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost( IndexedDBDispatcherHost* parent) : parent_(parent) { map_.set_check_on_null_data(true); } IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() { // TODO(alecflett): uncomment these when we find the source of these leaks. // DCHECK(transaction_size_map_.empty()); // DCHECK(transaction_url_map_.empty()); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() { // Abort outstanding transactions started by connections in the associated // front-end to unblock later transactions. This should only occur on unclean // (crash) or abrupt (process-kill) shutdowns. for (TransactionIDToDatabaseIDMap::iterator iter = transaction_database_map_.begin(); iter != transaction_database_map_.end();) { int64 transaction_id = iter->first; int32 ipc_database_id = iter->second; ++iter; WebIDBDatabase* database = map_.Lookup(ipc_database_id); if (database) { database->abort(transaction_id, WebIDBDatabaseError( WebKit::WebIDBDatabaseExceptionUnknownError)); } } DCHECK(transaction_database_map_.empty()); for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin(); iter != database_url_map_.end(); iter++) { WebIDBDatabase* database = map_.Lookup(iter->first); if (database) { database->close(); parent_->Context()->ConnectionClosed(iter->second, database); } } } bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived( const IPC::Message& message, bool* msg_is_ok) { bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::DatabaseDispatcherHost, message, *msg_is_ok) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore, OnCreateObjectStore) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore, OnDeleteObjectStore) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction, OnCreateTransaction) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPut) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady, OnSetIndexesReady) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void IndexedDBDispatcherHost::DatabaseDispatcherHost::Send( IPC::Message* message) { parent_->Send(message); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore( const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); database->createObjectStore( host_transaction_id, params.object_store_id, params.name, params.key_path, params.auto_increment); if (parent_->Context()->IsOverQuota( database_url_map_[params.ipc_database_id])) { database->abort(host_transaction_id, WebIDBDatabaseError( WebKit::WebIDBDatabaseExceptionQuotaError)); } } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore( int32 ipc_database_id, int64 transaction_id, int64 object_store_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, ipc_database_id); if (!database) return; database->deleteObjectStore(parent_->HostTransactionId(transaction_id), object_store_id); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction( const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) { WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; WebVector object_stores(params.object_store_ids.size()); for (size_t i = 0; i < params.object_store_ids.size(); ++i) object_stores[i] = params.object_store_ids[i]; int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); database->createTransaction( host_transaction_id, new IndexedDBDatabaseCallbacks(parent_, params.ipc_thread_id, params.ipc_database_callbacks_id), object_stores, params.mode); transaction_database_map_[host_transaction_id] = params.ipc_database_id; parent_->RegisterTransactionId(host_transaction_id, database_url_map_[params.ipc_database_id]); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose( int32 ipc_database_id) { WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, ipc_database_id); if (!database) return; database->close(); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed( int32 ipc_object_id) { WebIDBDatabase* database = map_.Lookup(ipc_object_id); parent_->Context()->ConnectionClosed(database_url_map_[ipc_object_id], database); database_url_map_.erase(ipc_object_id); parent_->DestroyObject(&map_, ipc_object_id); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet( const IndexedDBHostMsg_DatabaseGet_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; scoped_ptr callbacks( new IndexedDBCallbacks( parent_, params.ipc_thread_id, params.ipc_callbacks_id)); database->get(parent_->HostTransactionId(params.transaction_id), params.object_store_id, params.index_id, params.key_range, params.key_only, callbacks.release()); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut( const IndexedDBHostMsg_DatabasePut_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, params.ipc_thread_id, params.ipc_callbacks_id)); // Be careful with empty vectors. WebData value; if (params.value.size()) value.assign(¶ms.value.front(), params.value.size()); int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); database->put(host_transaction_id, params.object_store_id, value, params.key, params.put_mode, callbacks.release(), params.index_ids, params.index_keys); TransactionIDToSizeMap* map = &parent_->database_dispatcher_host_->transaction_size_map_; // Size can't be big enough to overflow because it represents the // actual bytes passed through IPC. (*map)[host_transaction_id] += params.value.size(); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys( const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); if (params.index_ids.size() != params.index_keys.size()) { database->abort(host_transaction_id, WebIDBDatabaseError( WebKit::WebIDBDatabaseExceptionUnknownError, "Malformed IPC message: index_ids.size() != index_keys.size()")); return; } database->setIndexKeys(host_transaction_id, params.object_store_id, params.primary_key, params.index_ids, params.index_keys); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady( int32 ipc_database_id, int64 transaction_id, int64 object_store_id, const std::vector& index_ids) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, ipc_database_id); if (!database) return; database->setIndexesReady(parent_->HostTransactionId(transaction_id), object_store_id, WebVector(index_ids)); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor( const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1)); database->openCursor( parent_->HostTransactionId(params.transaction_id), params.object_store_id, params.index_id, params.key_range, params.direction, params.key_only, params.task_type, callbacks.release()); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount( const IndexedDBHostMsg_DatabaseCount_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; scoped_ptr callbacks( new IndexedDBCallbacks( parent_, params.ipc_thread_id, params.ipc_callbacks_id)); database->count( parent_->HostTransactionId(params.transaction_id), params.object_store_id, params.index_id, params.key_range, callbacks.release()); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange( const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; scoped_ptr callbacks( new IndexedDBCallbacks( parent_, params.ipc_thread_id, params.ipc_callbacks_id)); database->deleteRange(parent_->HostTransactionId(params.transaction_id), params.object_store_id, params.key_range, callbacks.release()); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear( int32 ipc_thread_id, int32 ipc_callbacks_id, int32 ipc_database_id, int64 transaction_id, int64 object_store_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, ipc_database_id); if (!database) return; scoped_ptr callbacks( new IndexedDBCallbacks( parent_, ipc_thread_id, ipc_callbacks_id)); database->clear(parent_->HostTransactionId(transaction_id), object_store_id, callbacks.release()); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort( int32 ipc_database_id, int64 transaction_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, ipc_database_id); if (!database) return; database->abort(parent_->HostTransactionId(transaction_id)); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit( int32 ipc_database_id, int64 transaction_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, ipc_database_id); if (!database) return; int64 host_transaction_id = parent_->HostTransactionId(transaction_id); int64 transaction_size = transaction_size_map_[host_transaction_id]; if (transaction_size && parent_->Context()->WouldBeOverQuota( transaction_url_map_[host_transaction_id], transaction_size)) { database->abort(host_transaction_id, WebIDBDatabaseError( WebKit::WebIDBDatabaseExceptionQuotaError)); return; } database->commit(host_transaction_id); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex( const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, params.ipc_database_id); if (!database) return; int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); database->createIndex( host_transaction_id, params.object_store_id, params.index_id, params.name, params.key_path, params.unique, params.multi_entry); if (parent_->Context()->IsOverQuota( database_url_map_[params.ipc_database_id])) { database->abort(host_transaction_id, WebIDBDatabaseError( WebKit::WebIDBDatabaseExceptionQuotaError)); } } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex( int32 ipc_database_id, int64 transaction_id, int64 object_store_id, int64 index_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, ipc_database_id); if (!database) return; database->deleteIndex(parent_->HostTransactionId(transaction_id), object_store_id, index_id); } ////////////////////////////////////////////////////////////////////// // IndexedDBDispatcherHost::CursorDispatcherHost // IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost( IndexedDBDispatcherHost* parent) : parent_(parent) { map_.set_check_on_null_data(true); } IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() { } bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived( const IPC::Message& message, bool* msg_is_ok) { bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::CursorDispatcherHost, message, *msg_is_ok) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDelete, OnDelete) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void IndexedDBDispatcherHost::CursorDispatcherHost::Send( IPC::Message* message) { parent_->Send(message); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance( int32 ipc_cursor_id, int32 ipc_thread_id, int32 ipc_callbacks_id, unsigned long count) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess( &map_, ipc_cursor_id); if (!idb_cursor) return; idb_cursor->advance(count, new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id)); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue( int32 ipc_cursor_id, int32 ipc_thread_id, int32 ipc_callbacks_id, const IndexedDBKey& key) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); if (!idb_cursor) return; idb_cursor->continueFunction( key, new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id)); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch( int32 ipc_cursor_id, int32 ipc_thread_id, int32 ipc_callbacks_id, int n) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); if (!idb_cursor) return; idb_cursor->prefetchContinue( n, new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id)); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset( int32 ipc_cursor_id, int used_prefetches, int unused_prefetches) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); if (!idb_cursor) return; idb_cursor->prefetchReset(used_prefetches, unused_prefetches); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnDelete( int32 ipc_cursor_id, int32 ipc_thread_id, int32 ipc_callbacks_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); if (!idb_cursor) return; idb_cursor->deleteFunction( new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id)); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed( int32 ipc_object_id) { parent_->DestroyObject(&map_, ipc_object_id); } } // namespace content