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