// Copyright (c) 2011 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 "base/command_line.h" #include "base/utf_string_conversions.h" #include "content/browser/browser_thread.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/in_process_webkit/indexed_db_transaction_callbacks.h" #include "content/browser/renderer_host/render_message_filter.h" #include "content/browser/user_metrics.h" #include "content/common/content_switches.h" #include "content/common/indexed_db_messages.h" #include "content/common/result_codes.h" #include "googleurl/src/gurl.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMStringList.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBCursor.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabase.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabaseError.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBKeyRange.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBIndex.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBFactory.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBObjectStore.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBTransaction.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" #include "webkit/glue/webkit_glue.h" using WebKit::WebDOMStringList; using WebKit::WebExceptionCode; using WebKit::WebIDBCallbacks; using WebKit::WebIDBCursor; using WebKit::WebIDBDatabase; using WebKit::WebIDBDatabaseError; using WebKit::WebIDBIndex; using WebKit::WebIDBKey; using WebKit::WebIDBKeyRange; using WebKit::WebIDBObjectStore; using WebKit::WebIDBTransaction; using WebKit::WebSecurityOrigin; using WebKit::WebSerializedScriptValue; using WebKit::WebVector; namespace { template void DeleteOnWebKitThread(T* obj) { if (!BrowserThread::DeleteSoon(BrowserThread::WEBKIT, FROM_HERE, obj)) delete obj; } } IndexedDBDispatcherHost::IndexedDBDispatcherHost( int process_id, WebKitContext* webkit_context) : webkit_context_(webkit_context), ALLOW_THIS_IN_INITIALIZER_LIST(database_dispatcher_host_( new DatabaseDispatcherHost(this))), ALLOW_THIS_IN_INITIALIZER_LIST(index_dispatcher_host_( new IndexDispatcherHost(this))), ALLOW_THIS_IN_INITIALIZER_LIST(object_store_dispatcher_host_( new ObjectStoreDispatcherHost(this))), ALLOW_THIS_IN_INITIALIZER_LIST(cursor_dispatcher_host_( new CursorDispatcherHost(this))), ALLOW_THIS_IN_INITIALIZER_LIST(transaction_dispatcher_host_( new TransactionDispatcherHost(this))), process_id_(process_id) { DCHECK(webkit_context_.get()); } IndexedDBDispatcherHost::~IndexedDBDispatcherHost() { } void IndexedDBDispatcherHost::OnChannelClosing() { BrowserMessageFilter::OnChannelClosing(); bool success = BrowserThread::PostTask( BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(this, &IndexedDBDispatcherHost::ResetDispatcherHosts)); 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) || CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)); database_dispatcher_host_.reset(); index_dispatcher_host_.reset(); object_store_dispatcher_host_.reset(); cursor_dispatcher_host_.reset(); transaction_dispatcher_host_.reset(); } void IndexedDBDispatcherHost::OverrideThreadForMessage( const IPC::Message& message, BrowserThread::ID* thread) { if (IPC_MESSAGE_CLASS(message) == IndexedDBMsgStart) *thread = BrowserThread::WEBKIT; } bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message, bool* message_was_ok) { if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart) return false; DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); bool handled = database_dispatcher_host_->OnMessageReceived(message, message_was_ok) || index_dispatcher_host_->OnMessageReceived(message, message_was_ok) || object_store_dispatcher_host_->OnMessageReceived( message, message_was_ok) || cursor_dispatcher_host_->OnMessageReceived(message, message_was_ok) || transaction_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_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_.get()) { delete idb_cursor; return 0; } return cursor_dispatcher_host_->map_.Add(idb_cursor); } int32 IndexedDBDispatcherHost::Add(WebIDBDatabase* idb_database, const GURL& origin_url) { if (!database_dispatcher_host_.get()) { delete idb_database; return 0; } int32 idb_database_id = database_dispatcher_host_->map_.Add(idb_database); Context()->ConnectionOpened(origin_url); database_dispatcher_host_->database_url_map_[idb_database_id] = origin_url; return idb_database_id; } int32 IndexedDBDispatcherHost::Add(WebIDBIndex* idb_index) { if (!index_dispatcher_host_.get()) { delete idb_index; return 0; } if (!idb_index) return 0; return index_dispatcher_host_->map_.Add(idb_index); } int32 IndexedDBDispatcherHost::Add(WebIDBObjectStore* idb_object_store) { if (!object_store_dispatcher_host_.get()) { delete idb_object_store; return 0; } if (!idb_object_store) return 0; return object_store_dispatcher_host_->map_.Add(idb_object_store); } int32 IndexedDBDispatcherHost::Add(WebIDBTransaction* idb_transaction, const GURL& url) { if (!transaction_dispatcher_host_.get()) { delete idb_transaction; return 0; } int32 id = transaction_dispatcher_host_->map_.Add(idb_transaction); idb_transaction->setCallbacks(new IndexedDBTransactionCallbacks(this, id)); transaction_dispatcher_host_->transaction_url_map_[id] = url; return id; } void IndexedDBDispatcherHost::OnIDBFactoryOpen( const IndexedDBHostMsg_FactoryOpen_Params& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); FilePath base_path = webkit_context_->data_path(); FilePath indexed_db_path; if (!base_path.empty()) { indexed_db_path = base_path.Append( IndexedDBContext::kIndexedDBDirectory); } // TODO(jorlow): This doesn't support file:/// urls properly. We probably need // to add some toString method to WebSecurityOrigin that doesn't // return null for them. Look at // DatabaseUtil::GetOriginFromIdentifier. WebSecurityOrigin origin( WebSecurityOrigin::createFromDatabaseIdentifier(params.origin)); GURL origin_url(origin.toString()); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebKit::WebIDBFactory::BackingStoreType backingStoreType = WebKit::WebIDBFactory::LevelDBBackingStore; if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kSQLiteIndexedDatabase)) { backingStoreType = WebKit::WebIDBFactory::SQLiteBackingStore; } // TODO(dgrogan): Delete this magic constant once we've removed sqlite. static const uint64 kIncognitoSqliteBackendQuota = 50 * 1024 * 1024; // 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, new IndexedDBCallbacks(this, params.response_id, origin_url), origin, NULL, webkit_glue::FilePathToWebString(indexed_db_path), kIncognitoSqliteBackendQuota, backingStoreType); } void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase( const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) { FilePath base_path = webkit_context_->data_path(); FilePath indexed_db_path; if (!base_path.empty()) { indexed_db_path = base_path.Append( IndexedDBContext::kIndexedDBDirectory); } WebSecurityOrigin origin( WebSecurityOrigin::createFromDatabaseIdentifier(params.origin)); GURL url(origin.toString()); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); Context()->GetIDBFactory()->deleteDatabase( params.name, new IndexedDBCallbacks(this, params.response_id, url), WebSecurityOrigin::createFromDatabaseIdentifier(params.origin), NULL, webkit_glue::FilePathToWebString(indexed_db_path)); } void IndexedDBDispatcherHost::TransactionComplete(int32 transaction_id) { Context()->TransactionComplete( transaction_dispatcher_host_->transaction_url_map_[transaction_id]); } ////////////////////////////////////////////////////////////////////// // Helper templates. // template ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess( IDMap* map, int32 return_object_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); ObjectType* return_object = map->Lookup(return_object_id); if (!return_object) { UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_IDBMF")); BadMessageReceived(); } return return_object; } template void IndexedDBDispatcherHost::SyncGetter( IDMap* map, int32 object_id, ReplyType* reply, Method method) { MapObjectType* object = GetOrTerminateProcess(map, object_id); if (!object) return; *reply = (object->*method)(); } template void IndexedDBDispatcherHost::DestroyObject( IDMap* map, int32 object_id) { GetOrTerminateProcess(map, object_id); map->Remove(object_id); } ////////////////////////////////////////////////////////////////////// // IndexedDBDispatcherHost::DatabaseDispatcherHost // IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost( IndexedDBDispatcherHost* parent) : parent_(parent) { map_.set_check_on_null_data(true); } IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() { for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin(); iter != database_url_map_.end(); iter++) { parent_->Context()->ConnectionClosed(iter->second); } } 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_DatabaseName, OnName) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersion, OnVersion) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseObjectStoreNames, OnObjectStoreNames) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore, OnCreateObjectStore) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore, OnDeleteObjectStore) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetVersion, OnSetVersion) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseTransaction, OnTransaction) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpen, OnOpen) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void IndexedDBDispatcherHost::DatabaseDispatcherHost::Send( IPC::Message* message) { parent_->Send(message); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnName( int32 object_id, string16* name) { parent_->SyncGetter(&map_, object_id, name, &WebIDBDatabase::name); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersion( int32 object_id, string16* version) { parent_->SyncGetter( &map_, object_id, version, &WebIDBDatabase::version); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnObjectStoreNames( int32 idb_database_id, std::vector* object_stores) { WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess( &map_, idb_database_id); if (!idb_database) return; WebDOMStringList web_object_stores = idb_database->objectStoreNames(); object_stores->reserve(web_object_stores.length()); for (unsigned i = 0; i < web_object_stores.length(); ++i) object_stores->push_back(web_object_stores.item(i)); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore( const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params, int32* object_store_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess( &map_, params.idb_database_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, params.transaction_id); if (!idb_database || !idb_transaction) return; *ec = 0; WebIDBObjectStore* object_store = idb_database->createObjectStore( params.name, params.key_path, params.auto_increment, *idb_transaction, *ec); *object_store_id = *ec ? 0 : parent_->Add(object_store); if (parent_->Context()->IsOverQuota( database_url_map_[params.idb_database_id])) { idb_transaction->abort(); } } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore( int32 idb_database_id, const string16& name, int32 transaction_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess( &map_, idb_database_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, transaction_id); if (!idb_database || !idb_transaction) return; *ec = 0; idb_database->deleteObjectStore(name, *idb_transaction, *ec); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetVersion( int32 idb_database_id, int32 response_id, const string16& version, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess( &map_, idb_database_id); if (!idb_database) return; *ec = 0; idb_database->setVersion( version, new IndexedDBCallbacks(parent_, response_id, database_url_map_[idb_database_id]), *ec); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnTransaction( int32 idb_database_id, const std::vector& names, int32 mode, int32* idb_transaction_id, WebKit::WebExceptionCode* ec) { WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, idb_database_id); if (!database) return; WebDOMStringList object_stores; for (std::vector::const_iterator it = names.begin(); it != names.end(); ++it) { object_stores.append(*it); } *ec = 0; WebIDBTransaction* transaction = database->transaction( object_stores, mode, *ec); DCHECK(!transaction != !*ec); *idb_transaction_id = *ec ? 0 : parent_->Add(transaction, database_url_map_[idb_database_id]); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpen( int32 idb_database_id, int32 response_id) { WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, idb_database_id); database->open(new IndexedDBDatabaseCallbacks(parent_, response_id)); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose( int32 idb_database_id) { WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, idb_database_id); database->close(); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed( int32 object_id) { parent_->Context()->ConnectionClosed(database_url_map_[object_id]); database_url_map_.erase(object_id); parent_->DestroyObject(&map_, object_id); } ////////////////////////////////////////////////////////////////////// // IndexedDBDispatcherHost::IndexDispatcherHost // IndexedDBDispatcherHost::IndexDispatcherHost::IndexDispatcherHost( IndexedDBDispatcherHost* parent) : parent_(parent) { map_.set_check_on_null_data(true); } IndexedDBDispatcherHost::IndexDispatcherHost::~IndexDispatcherHost() { } bool IndexedDBDispatcherHost::IndexDispatcherHost::OnMessageReceived( const IPC::Message& message, bool* msg_is_ok) { bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::IndexDispatcherHost, message, *msg_is_ok) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexName, OnName) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexStoreName, OnStoreName) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexKeyPath, OnKeyPath) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexUnique, OnUnique) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexOpenObjectCursor, OnOpenObjectCursor) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexOpenKeyCursor, OnOpenKeyCursor) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexGetObject, OnGetObject) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexGetKey, OnGetKey) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexDestroyed, OnDestroyed) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void IndexedDBDispatcherHost::IndexDispatcherHost::Send( IPC::Message* message) { parent_->Send(message); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnName( int32 object_id, string16* name) { parent_->SyncGetter(&map_, object_id, name, &WebIDBIndex::name); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnStoreName( int32 object_id, string16* store_name) { parent_->SyncGetter( &map_, object_id, store_name, &WebIDBIndex::storeName); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnKeyPath( int32 object_id, NullableString16* key_path) { parent_->SyncGetter( &map_, object_id, key_path, &WebIDBIndex::keyPath); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnUnique( int32 object_id, bool* unique) { parent_->SyncGetter(&map_, object_id, unique, &WebIDBIndex::unique); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnOpenObjectCursor( const IndexedDBHostMsg_IndexOpenCursor_Params& params, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBIndex* idb_index = parent_->GetOrTerminateProcess( &map_, params.idb_index_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, params.transaction_id); if (!idb_transaction || !idb_index) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, params.response_id)); idb_index->openObjectCursor( WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open, params.upper_open), params.direction, callbacks.release(), *idb_transaction, *ec); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnOpenKeyCursor( const IndexedDBHostMsg_IndexOpenCursor_Params& params, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBIndex* idb_index = parent_->GetOrTerminateProcess( &map_, params.idb_index_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, params.transaction_id); if (!idb_transaction || !idb_index) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, params.response_id)); idb_index->openKeyCursor( WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open, params.upper_open), params.direction, callbacks.release(), *idb_transaction, *ec); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetObject( int idb_index_id, int32 response_id, const IndexedDBKey& key, int32 transaction_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBIndex* idb_index = parent_->GetOrTerminateProcess( &map_, idb_index_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, transaction_id); if (!idb_transaction || !idb_index) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, response_id)); idb_index->getObject(key, callbacks.release(), *idb_transaction, *ec); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetKey( int idb_index_id, int32 response_id, const IndexedDBKey& key, int32 transaction_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBIndex* idb_index = parent_->GetOrTerminateProcess( &map_, idb_index_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, transaction_id); if (!idb_transaction || !idb_index) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, response_id)); idb_index->getKey(key, callbacks.release(), *idb_transaction, *ec); } void IndexedDBDispatcherHost::IndexDispatcherHost::OnDestroyed( int32 object_id) { parent_->DestroyObject(&map_, object_id); } ////////////////////////////////////////////////////////////////////// // IndexedDBDispatcherHost::ObjectStoreDispatcherHost // IndexedDBDispatcherHost::ObjectStoreDispatcherHost::ObjectStoreDispatcherHost( IndexedDBDispatcherHost* parent) : parent_(parent) { map_.set_check_on_null_data(true); } IndexedDBDispatcherHost:: ObjectStoreDispatcherHost::~ObjectStoreDispatcherHost() { } bool IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnMessageReceived( const IPC::Message& message, bool* msg_is_ok) { bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::ObjectStoreDispatcherHost, message, *msg_is_ok) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreName, OnName) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreKeyPath, OnKeyPath) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreIndexNames, OnIndexNames) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreGet, OnGet) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStorePut, OnPut) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDelete, OnDelete) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreClear, OnClear) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreCreateIndex, OnCreateIndex) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreIndex, OnIndex) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDeleteIndex, OnDeleteIndex) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreOpenCursor, OnOpenCursor) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDestroyed, OnDestroyed) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::Send( IPC::Message* message) { parent_->Send(message); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnName( int32 object_id, string16* name) { parent_->SyncGetter( &map_, object_id, name, &WebIDBObjectStore::name); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnKeyPath( int32 object_id, NullableString16* keyPath) { parent_->SyncGetter( &map_, object_id, keyPath, &WebIDBObjectStore::keyPath); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnIndexNames( int32 idb_object_store_id, std::vector* index_names) { WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &map_, idb_object_store_id); if (!idb_object_store) return; WebDOMStringList web_index_names = idb_object_store->indexNames(); index_names->reserve(web_index_names.length()); for (unsigned i = 0; i < web_index_names.length(); ++i) index_names->push_back(web_index_names.item(i)); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnGet( int idb_object_store_id, int32 response_id, const IndexedDBKey& key, int32 transaction_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &map_, idb_object_store_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, transaction_id); if (!idb_transaction || !idb_object_store) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, response_id)); idb_object_store->get(key, callbacks.release(), *idb_transaction, *ec); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnPut( const IndexedDBHostMsg_ObjectStorePut_Params& params, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &map_, params.idb_object_store_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, params.transaction_id); if (!idb_transaction || !idb_object_store) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, params.response_id)); idb_object_store->put(params.serialized_value, params.key, params.put_mode, callbacks.release(), *idb_transaction, *ec); if (*ec) return; int64 size = UTF16ToUTF8(params.serialized_value.data()).size(); WebIDBTransactionIDToSizeMap* map = &parent_->transaction_dispatcher_host_->transaction_size_map_; (*map)[params.transaction_id] += size; } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDelete( int idb_object_store_id, int32 response_id, const IndexedDBKey& key, int32 transaction_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &map_, idb_object_store_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, transaction_id); if (!idb_transaction || !idb_object_store) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, response_id)); idb_object_store->deleteFunction( key, callbacks.release(), *idb_transaction, *ec); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnClear( int idb_object_store_id, int32 response_id, int32 transaction_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &map_, idb_object_store_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, transaction_id); if (!idb_transaction || !idb_object_store) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, response_id)); idb_object_store->clear(callbacks.release(), *idb_transaction, *ec); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnCreateIndex( const IndexedDBHostMsg_ObjectStoreCreateIndex_Params& params, int32* index_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &map_, params.idb_object_store_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, params.transaction_id); if (!idb_object_store || !idb_transaction) return; *ec = 0; WebIDBIndex* index = idb_object_store->createIndex( params.name, params.key_path, params.unique, *idb_transaction, *ec); *index_id = *ec ? 0 : parent_->Add(index); WebIDBObjectIDToURLMap* transaction_url_map = &parent_->transaction_dispatcher_host_->transaction_url_map_; if (parent_->Context()->IsOverQuota( (*transaction_url_map)[params.transaction_id])) { idb_transaction->abort(); } } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnIndex( int32 idb_object_store_id, const string16& name, int32* idb_index_id, WebKit::WebExceptionCode* ec) { WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &map_, idb_object_store_id); if (!idb_object_store) return; *ec = 0; WebIDBIndex* index = idb_object_store->index(name, *ec); *idb_index_id = parent_->Add(index); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDeleteIndex( int32 idb_object_store_id, const string16& name, int32 transaction_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &map_, idb_object_store_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, transaction_id); if (!idb_object_store || !idb_transaction) return; *ec = 0; idb_object_store->deleteIndex(name, *idb_transaction, *ec); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnOpenCursor( const IndexedDBHostMsg_ObjectStoreOpenCursor_Params& params, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess( &parent_->object_store_dispatcher_host_->map_, params.idb_object_store_id); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &parent_->transaction_dispatcher_host_->map_, params.transaction_id); if (!idb_transaction || !idb_object_store) return; *ec = 0; scoped_ptr callbacks( new IndexedDBCallbacks(parent_, params.response_id)); idb_object_store->openCursor( WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open, params.upper_open), params.direction, callbacks.release(), *idb_transaction, *ec); } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDestroyed( int32 object_id) { parent_->DestroyObject(&map_, object_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_CursorDirection, OnDirection) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorKey, OnKey) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrimaryKey, OnPrimaryKey) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorValue, OnValue) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorUpdate, OnUpdate) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue) 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::OnDirection( int32 object_id, int32* direction) { WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id); if (!idb_cursor) return; *direction = idb_cursor->direction(); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnKey( int32 object_id, IndexedDBKey* key) { WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id); if (!idb_cursor) return; *key = IndexedDBKey(idb_cursor->key()); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrimaryKey( int32 object_id, IndexedDBKey* primary_key) { WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id); if (!idb_cursor) return; *primary_key = IndexedDBKey(idb_cursor->primaryKey()); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnValue( int32 object_id, SerializedScriptValue* script_value) { WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id); if (!idb_cursor) return; *script_value = SerializedScriptValue(idb_cursor->value()); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnUpdate( int32 cursor_id, int32 response_id, const SerializedScriptValue& value, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id); if (!idb_cursor) return; *ec = 0; idb_cursor->update( value, new IndexedDBCallbacks(parent_, response_id), *ec); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue( int32 cursor_id, int32 response_id, const IndexedDBKey& key, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id); if (!idb_cursor) return; *ec = 0; idb_cursor->continueFunction( key, new IndexedDBCallbacks(parent_, response_id), *ec); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnDelete( int32 cursor_id, int32 response_id, WebKit::WebExceptionCode* ec) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id); if (!idb_cursor) return; *ec = 0; idb_cursor->deleteFunction( new IndexedDBCallbacks(parent_, response_id), *ec); } void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed( int32 object_id) { parent_->DestroyObject(&map_, object_id); } ////////////////////////////////////////////////////////////////////// // IndexedDBDispatcherHost::TransactionDispatcherHost // IndexedDBDispatcherHost::TransactionDispatcherHost::TransactionDispatcherHost( IndexedDBDispatcherHost* parent) : parent_(parent) { map_.set_check_on_null_data(true); } IndexedDBDispatcherHost:: TransactionDispatcherHost::~TransactionDispatcherHost() { MapType::iterator it(&map_); while (!it.IsAtEnd()) { it.GetCurrentValue()->abort(); it.Advance(); } } bool IndexedDBDispatcherHost::TransactionDispatcherHost::OnMessageReceived( const IPC::Message& message, bool* msg_is_ok) { bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::TransactionDispatcherHost, message, *msg_is_ok) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionAbort, OnAbort) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionMode, OnMode) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionObjectStore, OnObjectStore) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionDidCompleteTaskEvents, OnDidCompleteTaskEvents) IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionDestroyed, OnDestroyed) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void IndexedDBDispatcherHost::TransactionDispatcherHost::Send( IPC::Message* message) { parent_->Send(message); } void IndexedDBDispatcherHost::TransactionDispatcherHost::OnAbort( int32 transaction_id) { WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &map_, transaction_id); if (!idb_transaction) return; idb_transaction->abort(); } void IndexedDBDispatcherHost::TransactionDispatcherHost::OnMode( int32 transaction_id, int* mode) { WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &map_, transaction_id); if (!idb_transaction) return; *mode = idb_transaction->mode(); } void IndexedDBDispatcherHost::TransactionDispatcherHost::OnObjectStore( int32 transaction_id, const string16& name, int32* object_store_id, WebKit::WebExceptionCode* ec) { WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &map_, transaction_id); if (!idb_transaction) return; *ec = 0; WebIDBObjectStore* object_store = idb_transaction->objectStore(name, *ec); *object_store_id = object_store ? parent_->Add(object_store) : 0; } void IndexedDBDispatcherHost:: TransactionDispatcherHost::OnDidCompleteTaskEvents(int transaction_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess( &map_, transaction_id); if (!idb_transaction) return; // TODO(dgrogan): Tell the page the transaction aborted because of quota. if (parent_->Context()->WouldBeOverQuota( transaction_url_map_[transaction_id], transaction_size_map_[transaction_id])) { idb_transaction->abort(); return; } idb_transaction->didCompleteTaskEvents(); } void IndexedDBDispatcherHost::TransactionDispatcherHost::OnDestroyed( int32 object_id) { transaction_size_map_.erase(object_id); transaction_url_map_.erase(object_id); parent_->DestroyObject(&map_, object_id); }