indexed_db_dispatcher_host.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/indexed_db/indexed_db_dispatcher_host.h" 6 7#include <vector> 8 9#include "base/bind.h" 10#include "base/command_line.h" 11#include "base/files/file_path.h" 12#include "base/process.h" 13#include "base/process_util.h" 14#include "base/strings/utf_string_conversions.h" 15#include "content/browser/indexed_db/indexed_db_callbacks.h" 16#include "content/browser/indexed_db/indexed_db_connection.h" 17#include "content/browser/indexed_db/indexed_db_context_impl.h" 18#include "content/browser/indexed_db/indexed_db_cursor.h" 19#include "content/browser/indexed_db/indexed_db_database_callbacks.h" 20#include "content/browser/indexed_db/indexed_db_metadata.h" 21#include "content/browser/renderer_host/render_message_filter.h" 22#include "content/common/indexed_db/indexed_db_messages.h" 23#include "content/public/browser/browser_thread.h" 24#include "content/public/browser/user_metrics.h" 25#include "content/public/common/content_switches.h" 26#include "content/public/common/result_codes.h" 27#include "googleurl/src/gurl.h" 28#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h" 29#include "webkit/browser/database/database_util.h" 30#include "webkit/common/database/database_identifier.h" 31 32using webkit_database::DatabaseUtil; 33using WebKit::WebIDBKey; 34 35namespace content { 36 37IndexedDBDispatcherHost::IndexedDBDispatcherHost( 38 int ipc_process_id, 39 IndexedDBContextImpl* indexed_db_context) 40 : indexed_db_context_(indexed_db_context), 41 database_dispatcher_host_(new DatabaseDispatcherHost(this)), 42 cursor_dispatcher_host_(new CursorDispatcherHost(this)), 43 ipc_process_id_(ipc_process_id) { 44 DCHECK(indexed_db_context_); 45} 46 47IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {} 48 49void IndexedDBDispatcherHost::OnChannelClosing() { 50 BrowserMessageFilter::OnChannelClosing(); 51 52 bool success = indexed_db_context_->TaskRunner()->PostTask( 53 FROM_HERE, 54 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this)); 55 56 if (!success) 57 ResetDispatcherHosts(); 58} 59 60void IndexedDBDispatcherHost::OnDestruct() const { 61 // The last reference to the dispatcher may be a posted task, which would 62 // be destructed on the IndexedDB thread. Without this override, that would 63 // take the dispatcher with it. Since the dispatcher may be keeping the 64 // IndexedDBContext alive, it might be destructed to on its own thread, 65 // which is not supported. Ensure destruction runs on the IO thread instead. 66 BrowserThread::DeleteOnIOThread::Destruct(this); 67} 68 69void IndexedDBDispatcherHost::ResetDispatcherHosts() { 70 // It is important that the various *_dispatcher_host_ members are reset 71 // on the IndexedDB thread, since there might be incoming messages on that 72 // thread, and we must not reset the dispatcher hosts until after those 73 // messages are processed. 74 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 75 76 // Note that we explicitly separate CloseAll() from destruction of the 77 // DatabaseDispatcherHost, since CloseAll() can invoke callbacks which need to 78 // be dispatched through database_dispatcher_host_. 79 database_dispatcher_host_->CloseAll(); 80 database_dispatcher_host_.reset(); 81 cursor_dispatcher_host_.reset(); 82} 83 84base::TaskRunner* IndexedDBDispatcherHost::OverrideTaskRunnerForMessage( 85 const IPC::Message& message) { 86 if (IPC_MESSAGE_CLASS(message) == IndexedDBMsgStart) 87 return indexed_db_context_->TaskRunner(); 88 return NULL; 89} 90 91bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message, 92 bool* message_was_ok) { 93 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart) 94 return false; 95 96 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 97 98 bool handled = 99 database_dispatcher_host_->OnMessageReceived(message, message_was_ok) || 100 cursor_dispatcher_host_->OnMessageReceived(message, message_was_ok); 101 102 if (!handled) { 103 handled = true; 104 IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost, message, *message_was_ok) 105 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames, 106 OnIDBFactoryGetDatabaseNames) 107 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen) 108 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase, 109 OnIDBFactoryDeleteDatabase) 110 IPC_MESSAGE_UNHANDLED(handled = false) 111 IPC_END_MESSAGE_MAP() 112 } 113 return handled; 114} 115 116int32 IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) { 117 if (!cursor_dispatcher_host_) { 118 return 0; 119 } 120 return cursor_dispatcher_host_->map_.Add(cursor); 121} 122 123int32 IndexedDBDispatcherHost::Add(IndexedDBConnection* connection, 124 int32 ipc_thread_id, 125 const GURL& origin_url) { 126 if (!database_dispatcher_host_) { 127 delete connection; 128 return 0; 129 } 130 int32 ipc_database_id = database_dispatcher_host_->map_.Add(connection); 131 Context()->ConnectionOpened(origin_url, connection); 132 database_dispatcher_host_->database_url_map_[ipc_database_id] = origin_url; 133 return ipc_database_id; 134} 135 136void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id, 137 const GURL& url) { 138 if (!database_dispatcher_host_) 139 return; 140 database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url; 141} 142 143int64 IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id) { 144 // Inject the renderer process id into the transaction id, to 145 // uniquely identify this transaction, and effectively bind it to 146 // the renderer that initiated it. The lower 32 bits of 147 // transaction_id are guaranteed to be unique within that renderer. 148 base::ProcessId pid = base::GetProcId(peer_handle()); 149 DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits"; 150 COMPILE_ASSERT(sizeof(base::ProcessId) <= sizeof(int32), 151 Process_ID_must_fit_in_32_bits); 152 153 return transaction_id | (static_cast<uint64>(pid) << 32); 154} 155 156int64 IndexedDBDispatcherHost::RendererTransactionId( 157 int64 host_transaction_id) { 158 DCHECK(host_transaction_id >> 32 == base::GetProcId(peer_handle())) 159 << "Invalid renderer target for transaction id"; 160 return host_transaction_id & 0xffffffff; 161} 162 163IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) { 164 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 165 return cursor_dispatcher_host_->map_.Lookup(ipc_cursor_id); 166} 167 168::IndexedDBDatabaseMetadata IndexedDBDispatcherHost::ConvertMetadata( 169 const content::IndexedDBDatabaseMetadata& web_metadata) { 170 ::IndexedDBDatabaseMetadata metadata; 171 metadata.id = web_metadata.id; 172 metadata.name = web_metadata.name; 173 metadata.version = web_metadata.version; 174 metadata.int_version = web_metadata.int_version; 175 metadata.max_object_store_id = web_metadata.max_object_store_id; 176 177 for (content::IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator iter = 178 web_metadata.object_stores.begin(); 179 iter != web_metadata.object_stores.end(); 180 ++iter) { 181 182 const content::IndexedDBObjectStoreMetadata& web_store_metadata = 183 iter->second; 184 ::IndexedDBObjectStoreMetadata idb_store_metadata; 185 idb_store_metadata.id = web_store_metadata.id; 186 idb_store_metadata.name = web_store_metadata.name; 187 idb_store_metadata.keyPath = web_store_metadata.key_path; 188 idb_store_metadata.autoIncrement = web_store_metadata.auto_increment; 189 idb_store_metadata.max_index_id = web_store_metadata.max_index_id; 190 191 for (content::IndexedDBObjectStoreMetadata::IndexMap::const_iterator 192 index_iter = web_store_metadata.indexes.begin(); 193 index_iter != web_store_metadata.indexes.end(); 194 ++index_iter) { 195 const content::IndexedDBIndexMetadata& web_index_metadata = 196 index_iter->second; 197 ::IndexedDBIndexMetadata idb_index_metadata; 198 idb_index_metadata.id = web_index_metadata.id; 199 idb_index_metadata.name = web_index_metadata.name; 200 idb_index_metadata.keyPath = web_index_metadata.key_path; 201 idb_index_metadata.unique = web_index_metadata.unique; 202 idb_index_metadata.multiEntry = web_index_metadata.multi_entry; 203 idb_store_metadata.indexes.push_back(idb_index_metadata); 204 } 205 metadata.object_stores.push_back(idb_store_metadata); 206 } 207 return metadata; 208} 209 210void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames( 211 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) { 212 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 213 base::FilePath indexed_db_path = indexed_db_context_->data_path(); 214 215 Context()->GetIDBFactory()->GetDatabaseNames( 216 IndexedDBCallbacks::Create( 217 this, params.ipc_thread_id, params.ipc_callbacks_id), 218 params.database_identifier, 219 indexed_db_path); 220} 221 222void IndexedDBDispatcherHost::OnIDBFactoryOpen( 223 const IndexedDBHostMsg_FactoryOpen_Params& params) { 224 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 225 base::FilePath indexed_db_path = indexed_db_context_->data_path(); 226 227 GURL origin_url = 228 webkit_database::GetOriginFromIdentifier(params.database_identifier); 229 230 int64 host_transaction_id = HostTransactionId(params.transaction_id); 231 232 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore 233 // created) if this origin is already over quota. 234 scoped_refptr<IndexedDBCallbacks> callbacks = 235 IndexedDBCallbacks::Create(this, 236 params.ipc_thread_id, 237 params.ipc_callbacks_id, 238 params.ipc_database_callbacks_id, 239 host_transaction_id, 240 origin_url); 241 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks = 242 IndexedDBDatabaseCallbacks::Create( 243 this, params.ipc_thread_id, params.ipc_database_callbacks_id); 244 Context()->GetIDBFactory()-> 245 Open(params.name, 246 params.version, 247 host_transaction_id, 248 callbacks, 249 database_callbacks, 250 params.database_identifier, 251 indexed_db_path); 252} 253 254void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase( 255 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) { 256 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 257 base::FilePath indexed_db_path = indexed_db_context_->data_path(); 258 Context()->GetIDBFactory()->DeleteDatabase( 259 params.name, 260 IndexedDBCallbacks::Create( 261 this, params.ipc_thread_id, params.ipc_callbacks_id), 262 params.database_identifier, 263 indexed_db_path); 264} 265 266void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id, 267 bool committed) { 268 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 269 TransactionIDToURLMap& transaction_url_map = 270 database_dispatcher_host_->transaction_url_map_; 271 TransactionIDToSizeMap& transaction_size_map = 272 database_dispatcher_host_->transaction_size_map_; 273 TransactionIDToDatabaseIDMap& transaction_database_map = 274 database_dispatcher_host_->transaction_database_map_; 275 if (committed) 276 Context()->TransactionComplete(transaction_url_map[host_transaction_id]); 277 // It's unclear if std::map::erase(key) has defined behavior if the 278 // key is not found. 279 // TODO(alecflett): Remove if it is proven that it is safe. 280 if (transaction_url_map.find(host_transaction_id) != 281 transaction_url_map.end()) 282 transaction_url_map.erase(host_transaction_id); 283 if (transaction_size_map.find(host_transaction_id) != 284 transaction_size_map.end()) 285 transaction_size_map.erase(host_transaction_id); 286 if (transaction_database_map.find(host_transaction_id) != 287 transaction_database_map.end()) 288 transaction_database_map.erase(host_transaction_id); 289} 290 291////////////////////////////////////////////////////////////////////// 292// Helper templates. 293// 294 295template <typename ObjectType> 296ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess( 297 IDMap<ObjectType, IDMapOwnPointer>* map, 298 int32 ipc_return_object_id) { 299 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 300 ObjectType* return_object = map->Lookup(ipc_return_object_id); 301 if (!return_object) { 302 NOTREACHED() << "Uh oh, couldn't find object with id " 303 << ipc_return_object_id; 304 RecordAction(UserMetricsAction("BadMessageTerminate_IDBMF")); 305 BadMessageReceived(); 306 } 307 return return_object; 308} 309 310template <typename ObjectType> 311ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess( 312 RefIDMap<ObjectType>* map, 313 int32 ipc_return_object_id) { 314 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 315 ObjectType* return_object = map->Lookup(ipc_return_object_id); 316 if (!return_object) { 317 NOTREACHED() << "Uh oh, couldn't find object with id " 318 << ipc_return_object_id; 319 RecordAction(UserMetricsAction("BadMessageTerminate_IDBMF")); 320 BadMessageReceived(); 321 } 322 return return_object; 323} 324 325template <typename MapType> 326void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) { 327 GetOrTerminateProcess(map, ipc_object_id); 328 map->Remove(ipc_object_id); 329} 330 331////////////////////////////////////////////////////////////////////// 332// IndexedDBDispatcherHost::DatabaseDispatcherHost 333// 334 335IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost( 336 IndexedDBDispatcherHost* parent) 337 : parent_(parent) { 338 map_.set_check_on_null_data(true); 339} 340 341IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() { 342 // TODO(alecflett): uncomment these when we find the source of these leaks. 343 // DCHECK(transaction_size_map_.empty()); 344 // DCHECK(transaction_url_map_.empty()); 345} 346 347void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() { 348 DCHECK( 349 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 350 // Abort outstanding transactions started by connections in the associated 351 // front-end to unblock later transactions. This should only occur on unclean 352 // (crash) or abrupt (process-kill) shutdowns. 353 for (TransactionIDToDatabaseIDMap::iterator iter = 354 transaction_database_map_.begin(); 355 iter != transaction_database_map_.end();) { 356 int64 transaction_id = iter->first; 357 int32 ipc_database_id = iter->second; 358 ++iter; 359 IndexedDBConnection* connection = map_.Lookup(ipc_database_id); 360 if (connection) { 361 connection->database()->Abort( 362 transaction_id, 363 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError)); 364 } 365 } 366 DCHECK(transaction_database_map_.empty()); 367 368 for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin(); 369 iter != database_url_map_.end(); 370 iter++) { 371 IndexedDBConnection* connection = map_.Lookup(iter->first); 372 if (connection) { 373 connection->Close(); 374 parent_->Context()->ConnectionClosed(iter->second, connection); 375 } 376 } 377} 378 379bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived( 380 const IPC::Message& message, 381 bool* msg_is_ok) { 382 DCHECK( 383 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 384 bool handled = true; 385 IPC_BEGIN_MESSAGE_MAP_EX( 386 IndexedDBDispatcherHost::DatabaseDispatcherHost, message, *msg_is_ok) 387 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore, 388 OnCreateObjectStore) 389 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore, 390 OnDeleteObjectStore) 391 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction, 392 OnCreateTransaction) 393 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose) 394 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed) 395 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet) 396 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPut) 397 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys) 398 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady, 399 OnSetIndexesReady) 400 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor) 401 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount) 402 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange) 403 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear) 404 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex) 405 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex) 406 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort) 407 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit) 408 IPC_MESSAGE_UNHANDLED(handled = false) 409 IPC_END_MESSAGE_MAP() 410 return handled; 411} 412 413void IndexedDBDispatcherHost::DatabaseDispatcherHost::Send( 414 IPC::Message* message) { 415 parent_->Send(message); 416} 417 418void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore( 419 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) { 420 DCHECK( 421 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 422 IndexedDBConnection* connection = 423 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 424 if (!connection) 425 return; 426 427 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); 428 connection->database()->CreateObjectStore(host_transaction_id, 429 params.object_store_id, 430 params.name, 431 params.key_path, 432 params.auto_increment); 433 if (parent_->Context()->IsOverQuota( 434 database_url_map_[params.ipc_database_id])) { 435 connection->database()->Abort( 436 host_transaction_id, 437 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionQuotaError)); 438 } 439} 440 441void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore( 442 int32 ipc_database_id, 443 int64 transaction_id, 444 int64 object_store_id) { 445 DCHECK( 446 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 447 IndexedDBConnection* connection = 448 parent_->GetOrTerminateProcess(&map_, ipc_database_id); 449 if (!connection) 450 return; 451 452 connection->database()->DeleteObjectStore( 453 parent_->HostTransactionId(transaction_id), object_store_id); 454} 455 456void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction( 457 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) { 458 DCHECK( 459 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 460 IndexedDBConnection* connection = 461 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 462 if (!connection) 463 return; 464 465 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); 466 467 connection->database()->CreateTransaction(host_transaction_id, 468 connection, 469 params.object_store_ids, 470 params.mode); 471 transaction_database_map_[host_transaction_id] = params.ipc_database_id; 472 parent_->RegisterTransactionId(host_transaction_id, 473 database_url_map_[params.ipc_database_id]); 474} 475 476void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose( 477 int32 ipc_database_id) { 478 DCHECK( 479 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 480 IndexedDBConnection* connection = 481 parent_->GetOrTerminateProcess(&map_, ipc_database_id); 482 if (!connection) 483 return; 484 connection->Close(); 485} 486 487void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed( 488 int32 ipc_object_id) { 489 DCHECK( 490 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 491 IndexedDBConnection* connection = map_.Lookup(ipc_object_id); 492 parent_->Context() 493 ->ConnectionClosed(database_url_map_[ipc_object_id], connection); 494 database_url_map_.erase(ipc_object_id); 495 parent_->DestroyObject(&map_, ipc_object_id); 496} 497 498void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet( 499 const IndexedDBHostMsg_DatabaseGet_Params& params) { 500 DCHECK( 501 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 502 IndexedDBConnection* connection = 503 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 504 if (!connection) 505 return; 506 507 scoped_refptr<IndexedDBCallbacks> callbacks(IndexedDBCallbacks::Create( 508 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); 509 connection->database()->Get( 510 parent_->HostTransactionId(params.transaction_id), 511 params.object_store_id, 512 params.index_id, 513 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)), 514 params.key_only, 515 callbacks); 516} 517 518void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut( 519 const IndexedDBHostMsg_DatabasePut_Params& params) { 520 DCHECK( 521 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 522 523 IndexedDBConnection* connection = 524 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 525 if (!connection) 526 return; 527 scoped_refptr<IndexedDBCallbacks> callbacks(IndexedDBCallbacks::Create( 528 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); 529 530 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); 531 // TODO(alecflett): Avoid a copy here. 532 std::vector<char> value_copy = params.value; 533 connection->database()->Put( 534 host_transaction_id, 535 params.object_store_id, 536 &value_copy, 537 make_scoped_ptr(new IndexedDBKey(params.key)), 538 static_cast<IndexedDBDatabase::PutMode>(params.put_mode), 539 callbacks, 540 params.index_ids, 541 params.index_keys); 542 TransactionIDToSizeMap* map = 543 &parent_->database_dispatcher_host_->transaction_size_map_; 544 // Size can't be big enough to overflow because it represents the 545 // actual bytes passed through IPC. 546 (*map)[host_transaction_id] += params.value.size(); 547} 548 549void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys( 550 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) { 551 DCHECK( 552 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 553 IndexedDBConnection* connection = 554 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 555 if (!connection) 556 return; 557 558 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); 559 if (params.index_ids.size() != params.index_keys.size()) { 560 connection->database()->Abort( 561 host_transaction_id, 562 IndexedDBDatabaseError( 563 WebKit::WebIDBDatabaseExceptionUnknownError, 564 "Malformed IPC message: index_ids.size() != index_keys.size()")); 565 return; 566 } 567 568 connection->database()->SetIndexKeys( 569 host_transaction_id, 570 params.object_store_id, 571 make_scoped_ptr(new IndexedDBKey(params.primary_key)), 572 params.index_ids, 573 params.index_keys); 574} 575 576void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady( 577 int32 ipc_database_id, 578 int64 transaction_id, 579 int64 object_store_id, 580 const std::vector<int64>& index_ids) { 581 DCHECK( 582 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 583 IndexedDBConnection* connection = 584 parent_->GetOrTerminateProcess(&map_, ipc_database_id); 585 if (!connection) 586 return; 587 588 connection->database()->SetIndexesReady( 589 parent_->HostTransactionId(transaction_id), object_store_id, index_ids); 590} 591 592void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor( 593 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) { 594 DCHECK( 595 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 596 IndexedDBConnection* connection = 597 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 598 if (!connection) 599 return; 600 601 scoped_refptr<IndexedDBCallbacks> callbacks(IndexedDBCallbacks::Create( 602 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1)); 603 connection->database()->OpenCursor( 604 parent_->HostTransactionId(params.transaction_id), 605 params.object_store_id, 606 params.index_id, 607 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)), 608 static_cast<indexed_db::CursorDirection>(params.direction), 609 params.key_only, 610 static_cast<IndexedDBDatabase::TaskType>(params.task_type), 611 callbacks); 612} 613 614void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount( 615 const IndexedDBHostMsg_DatabaseCount_Params& params) { 616 DCHECK( 617 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 618 IndexedDBConnection* connection = 619 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 620 if (!connection) 621 return; 622 623 scoped_refptr<IndexedDBCallbacks> callbacks(IndexedDBCallbacks::Create( 624 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); 625 connection->database()->Count( 626 parent_->HostTransactionId(params.transaction_id), 627 params.object_store_id, 628 params.index_id, 629 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)), 630 callbacks); 631} 632 633void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange( 634 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) { 635 DCHECK( 636 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 637 IndexedDBConnection* connection = 638 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 639 if (!connection) 640 return; 641 642 scoped_refptr<IndexedDBCallbacks> callbacks(IndexedDBCallbacks::Create( 643 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); 644 connection->database()->DeleteRange( 645 parent_->HostTransactionId(params.transaction_id), 646 params.object_store_id, 647 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)), 648 callbacks); 649} 650 651void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear( 652 int32 ipc_thread_id, 653 int32 ipc_callbacks_id, 654 int32 ipc_database_id, 655 int64 transaction_id, 656 int64 object_store_id) { 657 DCHECK( 658 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 659 IndexedDBConnection* connection = 660 parent_->GetOrTerminateProcess(&map_, ipc_database_id); 661 if (!connection) 662 return; 663 664 scoped_refptr<IndexedDBCallbacks> callbacks( 665 IndexedDBCallbacks::Create(parent_, ipc_thread_id, ipc_callbacks_id)); 666 667 connection->database()->Clear( 668 parent_->HostTransactionId(transaction_id), object_store_id, callbacks); 669} 670 671void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort( 672 int32 ipc_database_id, 673 int64 transaction_id) { 674 DCHECK( 675 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 676 IndexedDBConnection* connection = 677 parent_->GetOrTerminateProcess(&map_, ipc_database_id); 678 if (!connection) 679 return; 680 681 connection->database()->Abort(parent_->HostTransactionId(transaction_id)); 682} 683 684void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit( 685 int32 ipc_database_id, 686 int64 transaction_id) { 687 DCHECK( 688 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 689 IndexedDBConnection* connection = 690 parent_->GetOrTerminateProcess(&map_, ipc_database_id); 691 if (!connection) 692 return; 693 694 int64 host_transaction_id = parent_->HostTransactionId(transaction_id); 695 int64 transaction_size = transaction_size_map_[host_transaction_id]; 696 if (transaction_size && 697 parent_->Context()->WouldBeOverQuota( 698 transaction_url_map_[host_transaction_id], transaction_size)) { 699 connection->database()->Abort( 700 host_transaction_id, 701 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionQuotaError)); 702 return; 703 } 704 705 connection->database()->Commit(host_transaction_id); 706} 707 708void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex( 709 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) { 710 DCHECK( 711 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 712 IndexedDBConnection* connection = 713 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); 714 if (!connection) 715 return; 716 717 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id); 718 connection->database()->CreateIndex(host_transaction_id, 719 params.object_store_id, 720 params.index_id, 721 params.name, 722 params.key_path, 723 params.unique, 724 params.multi_entry); 725 if (parent_->Context()->IsOverQuota( 726 database_url_map_[params.ipc_database_id])) { 727 connection->database()->Abort( 728 host_transaction_id, 729 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionQuotaError)); 730 } 731} 732 733void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex( 734 int32 ipc_database_id, 735 int64 transaction_id, 736 int64 object_store_id, 737 int64 index_id) { 738 DCHECK( 739 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 740 IndexedDBConnection* connection = 741 parent_->GetOrTerminateProcess(&map_, ipc_database_id); 742 if (!connection) 743 return; 744 745 connection->database()->DeleteIndex( 746 parent_->HostTransactionId(transaction_id), object_store_id, index_id); 747} 748 749////////////////////////////////////////////////////////////////////// 750// IndexedDBDispatcherHost::CursorDispatcherHost 751// 752 753IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost( 754 IndexedDBDispatcherHost* parent) 755 : parent_(parent) { 756 map_.set_check_on_null_data(true); 757} 758 759IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {} 760 761bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived( 762 const IPC::Message& message, 763 bool* msg_is_ok) { 764 DCHECK( 765 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 766 767 bool handled = true; 768 IPC_BEGIN_MESSAGE_MAP_EX( 769 IndexedDBDispatcherHost::CursorDispatcherHost, message, *msg_is_ok) 770 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance) 771 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue) 772 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch) 773 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset) 774 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed) 775 IPC_MESSAGE_UNHANDLED(handled = false) 776 IPC_END_MESSAGE_MAP() 777 return handled; 778} 779 780void IndexedDBDispatcherHost::CursorDispatcherHost::Send( 781 IPC::Message* message) { 782 parent_->Send(message); 783} 784 785void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance( 786 int32 ipc_cursor_id, 787 int32 ipc_thread_id, 788 int32 ipc_callbacks_id, 789 unsigned long count) { 790 DCHECK( 791 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 792 IndexedDBCursor* idb_cursor = 793 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); 794 if (!idb_cursor) 795 return; 796 797 idb_cursor->Advance( 798 count, 799 IndexedDBCallbacks::Create( 800 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id)); 801} 802 803void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue( 804 int32 ipc_cursor_id, 805 int32 ipc_thread_id, 806 int32 ipc_callbacks_id, 807 const IndexedDBKey& key) { 808 DCHECK( 809 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 810 IndexedDBCursor* idb_cursor = 811 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); 812 if (!idb_cursor) 813 return; 814 815 idb_cursor->ContinueFunction( 816 make_scoped_ptr(new IndexedDBKey(key)), 817 IndexedDBCallbacks::Create( 818 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id)); 819} 820 821void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch( 822 int32 ipc_cursor_id, 823 int32 ipc_thread_id, 824 int32 ipc_callbacks_id, 825 int n) { 826 DCHECK( 827 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 828 IndexedDBCursor* idb_cursor = 829 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); 830 if (!idb_cursor) 831 return; 832 833 idb_cursor->PrefetchContinue( 834 n, 835 IndexedDBCallbacks::Create( 836 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id)); 837} 838 839void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset( 840 int32 ipc_cursor_id, 841 int used_prefetches, 842 int unused_prefetches) { 843 DCHECK( 844 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 845 IndexedDBCursor* idb_cursor = 846 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); 847 if (!idb_cursor) 848 return; 849 850 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches); 851} 852 853void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed( 854 int32 ipc_object_id) { 855 DCHECK( 856 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); 857 parent_->DestroyObject(&map_, ipc_object_id); 858} 859 860} // namespace content 861