1 // Copyright 2013 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/child/indexed_db/indexed_db_dispatcher.h" 6 7 #include <utility> 8 9 #include "base/format_macros.h" 10 #include "base/lazy_instance.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/threading/thread_local.h" 13 #include "content/child/indexed_db/indexed_db_key_builders.h" 14 #include "content/child/indexed_db/webidbcursor_impl.h" 15 #include "content/child/indexed_db/webidbdatabase_impl.h" 16 #include "content/child/thread_safe_sender.h" 17 #include "content/common/indexed_db/indexed_db_constants.h" 18 #include "content/common/indexed_db/indexed_db_messages.h" 19 #include "ipc/ipc_channel.h" 20 #include "third_party/WebKit/public/platform/WebIDBDatabaseCallbacks.h" 21 #include "third_party/WebKit/public/platform/WebIDBDatabaseError.h" 22 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h" 23 24 using blink::WebBlobInfo; 25 using blink::WebData; 26 using blink::WebIDBCallbacks; 27 using blink::WebIDBCursor; 28 using blink::WebIDBDatabase; 29 using blink::WebIDBDatabaseCallbacks; 30 using blink::WebIDBDatabaseError; 31 using blink::WebIDBKey; 32 using blink::WebIDBMetadata; 33 using blink::WebString; 34 using blink::WebVector; 35 using base::ThreadLocalPointer; 36 37 namespace content { 38 static base::LazyInstance<ThreadLocalPointer<IndexedDBDispatcher> >::Leaky 39 g_idb_dispatcher_tls = LAZY_INSTANCE_INITIALIZER; 40 41 namespace { 42 43 IndexedDBDispatcher* const kHasBeenDeleted = 44 reinterpret_cast<IndexedDBDispatcher*>(0x1); 45 46 } // unnamed namespace 47 48 const size_t kMaxIDBMessageOverhead = 1024 * 1024; // 1MB; arbitrarily chosen. 49 const size_t kMaxIDBValueSizeInBytes = 50 IPC::Channel::kMaximumMessageSize - kMaxIDBMessageOverhead; 51 52 IndexedDBDispatcher::IndexedDBDispatcher(ThreadSafeSender* thread_safe_sender) 53 : thread_safe_sender_(thread_safe_sender) { 54 g_idb_dispatcher_tls.Pointer()->Set(this); 55 } 56 57 IndexedDBDispatcher::~IndexedDBDispatcher() { 58 // Clear any pending callbacks - which may result in dispatch requests - 59 // before marking the dispatcher as deleted. 60 pending_callbacks_.Clear(); 61 pending_database_callbacks_.Clear(); 62 63 DCHECK(pending_callbacks_.IsEmpty()); 64 DCHECK(pending_database_callbacks_.IsEmpty()); 65 66 g_idb_dispatcher_tls.Pointer()->Set(kHasBeenDeleted); 67 } 68 69 IndexedDBDispatcher* IndexedDBDispatcher::ThreadSpecificInstance( 70 ThreadSafeSender* thread_safe_sender) { 71 if (g_idb_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) { 72 NOTREACHED() << "Re-instantiating TLS IndexedDBDispatcher."; 73 g_idb_dispatcher_tls.Pointer()->Set(NULL); 74 } 75 if (g_idb_dispatcher_tls.Pointer()->Get()) 76 return g_idb_dispatcher_tls.Pointer()->Get(); 77 78 IndexedDBDispatcher* dispatcher = new IndexedDBDispatcher(thread_safe_sender); 79 if (WorkerTaskRunner::Instance()->CurrentWorkerId()) 80 WorkerTaskRunner::Instance()->AddStopObserver(dispatcher); 81 return dispatcher; 82 } 83 84 void IndexedDBDispatcher::OnWorkerRunLoopStopped() { delete this; } 85 86 WebIDBMetadata IndexedDBDispatcher::ConvertMetadata( 87 const IndexedDBDatabaseMetadata& idb_metadata) { 88 WebIDBMetadata web_metadata; 89 web_metadata.id = idb_metadata.id; 90 web_metadata.name = idb_metadata.name; 91 web_metadata.version = idb_metadata.version; 92 web_metadata.intVersion = idb_metadata.int_version; 93 web_metadata.maxObjectStoreId = idb_metadata.max_object_store_id; 94 web_metadata.objectStores = 95 WebVector<WebIDBMetadata::ObjectStore>(idb_metadata.object_stores.size()); 96 97 for (size_t i = 0; i < idb_metadata.object_stores.size(); ++i) { 98 const IndexedDBObjectStoreMetadata& idb_store_metadata = 99 idb_metadata.object_stores[i]; 100 WebIDBMetadata::ObjectStore& web_store_metadata = 101 web_metadata.objectStores[i]; 102 103 web_store_metadata.id = idb_store_metadata.id; 104 web_store_metadata.name = idb_store_metadata.name; 105 web_store_metadata.keyPath = 106 WebIDBKeyPathBuilder::Build(idb_store_metadata.keyPath); 107 web_store_metadata.autoIncrement = idb_store_metadata.autoIncrement; 108 web_store_metadata.maxIndexId = idb_store_metadata.max_index_id; 109 web_store_metadata.indexes = 110 WebVector<WebIDBMetadata::Index>(idb_store_metadata.indexes.size()); 111 112 for (size_t j = 0; j < idb_store_metadata.indexes.size(); ++j) { 113 const IndexedDBIndexMetadata& idb_index_metadata = 114 idb_store_metadata.indexes[j]; 115 WebIDBMetadata::Index& web_index_metadata = web_store_metadata.indexes[j]; 116 117 web_index_metadata.id = idb_index_metadata.id; 118 web_index_metadata.name = idb_index_metadata.name; 119 web_index_metadata.keyPath = 120 WebIDBKeyPathBuilder::Build(idb_index_metadata.keyPath); 121 web_index_metadata.unique = idb_index_metadata.unique; 122 web_index_metadata.multiEntry = idb_index_metadata.multiEntry; 123 } 124 } 125 126 return web_metadata; 127 } 128 129 void IndexedDBDispatcher::OnMessageReceived(const IPC::Message& msg) { 130 bool handled = true; 131 IPC_BEGIN_MESSAGE_MAP(IndexedDBDispatcher, msg) 132 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBCursor, 133 OnSuccessOpenCursor) 134 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorAdvance, 135 OnSuccessCursorContinue) 136 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorContinue, 137 OnSuccessCursorContinue) 138 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorPrefetch, 139 OnSuccessCursorPrefetch) 140 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBDatabase, 141 OnSuccessIDBDatabase) 142 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIndexedDBKey, 143 OnSuccessIndexedDBKey) 144 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessStringList, 145 OnSuccessStringList) 146 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessValue, OnSuccessValue) 147 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessValueWithKey, 148 OnSuccessValueWithKey) 149 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessInteger, OnSuccessInteger) 150 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessUndefined, 151 OnSuccessUndefined) 152 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksError, OnError) 153 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksIntBlocked, OnIntBlocked) 154 IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksUpgradeNeeded, OnUpgradeNeeded) 155 IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksForcedClose, 156 OnForcedClose) 157 IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksIntVersionChange, 158 OnIntVersionChange) 159 IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksAbort, OnAbort) 160 IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksComplete, OnComplete) 161 IPC_MESSAGE_UNHANDLED(handled = false) 162 IPC_END_MESSAGE_MAP() 163 // If a message gets here, IndexedDBMessageFilter already determined that it 164 // is an IndexedDB message. 165 DCHECK(handled) << "Didn't handle a message defined at line " 166 << IPC_MESSAGE_ID_LINE(msg.type()); 167 } 168 169 bool IndexedDBDispatcher::Send(IPC::Message* msg) { 170 return thread_safe_sender_->Send(msg); 171 } 172 173 void IndexedDBDispatcher::RequestIDBCursorAdvance( 174 unsigned long count, 175 WebIDBCallbacks* callbacks_ptr, 176 int32 ipc_cursor_id, 177 int64 transaction_id) { 178 // Reset all cursor prefetch caches except for this cursor. 179 ResetCursorPrefetchCaches(transaction_id, ipc_cursor_id); 180 181 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 182 183 int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); 184 Send(new IndexedDBHostMsg_CursorAdvance( 185 ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, count)); 186 } 187 188 void IndexedDBDispatcher::RequestIDBCursorContinue( 189 const IndexedDBKey& key, 190 const IndexedDBKey& primary_key, 191 WebIDBCallbacks* callbacks_ptr, 192 int32 ipc_cursor_id, 193 int64 transaction_id) { 194 // Reset all cursor prefetch caches except for this cursor. 195 ResetCursorPrefetchCaches(transaction_id, ipc_cursor_id); 196 197 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 198 199 int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); 200 Send(new IndexedDBHostMsg_CursorContinue( 201 ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, key, primary_key)); 202 } 203 204 void IndexedDBDispatcher::RequestIDBCursorPrefetch( 205 int n, 206 WebIDBCallbacks* callbacks_ptr, 207 int32 ipc_cursor_id) { 208 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 209 210 int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); 211 Send(new IndexedDBHostMsg_CursorPrefetch( 212 ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, n)); 213 } 214 215 void IndexedDBDispatcher::RequestIDBCursorPrefetchReset(int used_prefetches, 216 int unused_prefetches, 217 int32 ipc_cursor_id) { 218 Send(new IndexedDBHostMsg_CursorPrefetchReset( 219 ipc_cursor_id, used_prefetches, unused_prefetches)); 220 } 221 222 void IndexedDBDispatcher::RequestIDBFactoryOpen( 223 const base::string16& name, 224 int64 version, 225 int64 transaction_id, 226 WebIDBCallbacks* callbacks_ptr, 227 WebIDBDatabaseCallbacks* database_callbacks_ptr, 228 const std::string& database_identifier) { 229 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 230 scoped_ptr<WebIDBDatabaseCallbacks> database_callbacks( 231 database_callbacks_ptr); 232 233 IndexedDBHostMsg_FactoryOpen_Params params; 234 params.ipc_thread_id = CurrentWorkerId(); 235 params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); 236 params.ipc_database_callbacks_id = 237 pending_database_callbacks_.Add(database_callbacks.release()); 238 params.database_identifier = database_identifier; 239 params.name = name; 240 params.transaction_id = transaction_id; 241 params.version = version; 242 Send(new IndexedDBHostMsg_FactoryOpen(params)); 243 } 244 245 void IndexedDBDispatcher::RequestIDBFactoryGetDatabaseNames( 246 WebIDBCallbacks* callbacks_ptr, 247 const std::string& database_identifier) { 248 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 249 250 IndexedDBHostMsg_FactoryGetDatabaseNames_Params params; 251 params.ipc_thread_id = CurrentWorkerId(); 252 params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); 253 params.database_identifier = database_identifier; 254 Send(new IndexedDBHostMsg_FactoryGetDatabaseNames(params)); 255 } 256 257 void IndexedDBDispatcher::RequestIDBFactoryDeleteDatabase( 258 const base::string16& name, 259 WebIDBCallbacks* callbacks_ptr, 260 const std::string& database_identifier) { 261 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 262 263 IndexedDBHostMsg_FactoryDeleteDatabase_Params params; 264 params.ipc_thread_id = CurrentWorkerId(); 265 params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); 266 params.database_identifier = database_identifier; 267 params.name = name; 268 Send(new IndexedDBHostMsg_FactoryDeleteDatabase(params)); 269 } 270 271 void IndexedDBDispatcher::RequestIDBDatabaseClose( 272 int32 ipc_database_id, 273 int32 ipc_database_callbacks_id) { 274 Send(new IndexedDBHostMsg_DatabaseClose(ipc_database_id)); 275 // There won't be pending database callbacks if the transaction was aborted in 276 // the initial upgradeneeded event handler. 277 if (pending_database_callbacks_.Lookup(ipc_database_callbacks_id)) 278 pending_database_callbacks_.Remove(ipc_database_callbacks_id); 279 } 280 281 void IndexedDBDispatcher::RequestIDBDatabaseCreateTransaction( 282 int32 ipc_database_id, 283 int64 transaction_id, 284 WebIDBDatabaseCallbacks* database_callbacks_ptr, 285 WebVector<long long> object_store_ids, 286 WebIDBDatabase::TransactionMode mode) { 287 scoped_ptr<WebIDBDatabaseCallbacks> database_callbacks( 288 database_callbacks_ptr); 289 IndexedDBHostMsg_DatabaseCreateTransaction_Params params; 290 params.ipc_thread_id = CurrentWorkerId(); 291 params.ipc_database_id = ipc_database_id; 292 params.transaction_id = transaction_id; 293 params.ipc_database_callbacks_id = 294 pending_database_callbacks_.Add(database_callbacks.release()); 295 params.object_store_ids 296 .assign(object_store_ids.data(), 297 object_store_ids.data() + object_store_ids.size()); 298 params.mode = mode; 299 300 Send(new IndexedDBHostMsg_DatabaseCreateTransaction(params)); 301 } 302 303 void IndexedDBDispatcher::RequestIDBDatabaseGet( 304 int32 ipc_database_id, 305 int64 transaction_id, 306 int64 object_store_id, 307 int64 index_id, 308 const IndexedDBKeyRange& key_range, 309 bool key_only, 310 WebIDBCallbacks* callbacks) { 311 ResetCursorPrefetchCaches(transaction_id, kAllCursors); 312 IndexedDBHostMsg_DatabaseGet_Params params; 313 init_params(¶ms, callbacks); 314 params.ipc_database_id = ipc_database_id; 315 params.transaction_id = transaction_id; 316 params.object_store_id = object_store_id; 317 params.index_id = index_id; 318 params.key_range = key_range; 319 params.key_only = key_only; 320 Send(new IndexedDBHostMsg_DatabaseGet(params)); 321 } 322 323 void IndexedDBDispatcher::RequestIDBDatabasePut( 324 int32 ipc_database_id, 325 int64 transaction_id, 326 int64 object_store_id, 327 const WebData& value, 328 const blink::WebVector<WebBlobInfo>& web_blob_info, 329 const IndexedDBKey& key, 330 WebIDBDatabase::PutMode put_mode, 331 WebIDBCallbacks* callbacks, 332 const WebVector<long long>& index_ids, 333 const WebVector<WebVector<WebIDBKey> >& index_keys) { 334 335 if (value.size() + key.size_estimate() > kMaxIDBValueSizeInBytes) { 336 callbacks->onError(WebIDBDatabaseError( 337 blink::WebIDBDatabaseExceptionUnknownError, 338 WebString::fromUTF8(base::StringPrintf( 339 "The serialized value is too large" 340 " (size=%" PRIuS " bytes, max=%" PRIuS " bytes).", 341 value.size(), 342 kMaxIDBValueSizeInBytes).c_str()))); 343 return; 344 } 345 346 ResetCursorPrefetchCaches(transaction_id, kAllCursors); 347 IndexedDBHostMsg_DatabasePut_Params params; 348 init_params(¶ms, callbacks); 349 params.ipc_database_id = ipc_database_id; 350 params.transaction_id = transaction_id; 351 params.object_store_id = object_store_id; 352 353 params.value.assign(value.data(), value.data() + value.size()); 354 params.key = key; 355 params.put_mode = put_mode; 356 357 DCHECK_EQ(index_ids.size(), index_keys.size()); 358 params.index_keys.resize(index_ids.size()); 359 for (size_t i = 0, len = index_ids.size(); i < len; ++i) { 360 params.index_keys[i].first = index_ids[i]; 361 params.index_keys[i].second.resize(index_keys[i].size()); 362 for (size_t j = 0; j < index_keys[i].size(); ++j) { 363 params.index_keys[i].second[j] = 364 IndexedDBKey(IndexedDBKeyBuilder::Build(index_keys[i][j])); 365 } 366 } 367 368 params.blob_or_file_info.resize(web_blob_info.size()); 369 for (size_t i = 0; i < web_blob_info.size(); ++i) { 370 const WebBlobInfo& info = web_blob_info[i]; 371 IndexedDBMsg_BlobOrFileInfo& blob_or_file_info = 372 params.blob_or_file_info[i]; 373 blob_or_file_info.is_file = info.isFile(); 374 if (info.isFile()) { 375 blob_or_file_info.file_path = info.filePath(); 376 blob_or_file_info.file_name = info.fileName(); 377 blob_or_file_info.last_modified = info.lastModified(); 378 } 379 blob_or_file_info.size = info.size(); 380 blob_or_file_info.uuid = info.uuid().latin1(); 381 DCHECK(blob_or_file_info.uuid.size()); 382 blob_or_file_info.mime_type = info.type(); 383 } 384 385 Send(new IndexedDBHostMsg_DatabasePut(params)); 386 } 387 388 void IndexedDBDispatcher::RequestIDBDatabaseOpenCursor( 389 int32 ipc_database_id, 390 int64 transaction_id, 391 int64 object_store_id, 392 int64 index_id, 393 const IndexedDBKeyRange& key_range, 394 WebIDBCursor::Direction direction, 395 bool key_only, 396 WebIDBDatabase::TaskType task_type, 397 WebIDBCallbacks* callbacks) { 398 ResetCursorPrefetchCaches(transaction_id, kAllCursors); 399 IndexedDBHostMsg_DatabaseOpenCursor_Params params; 400 init_params(¶ms, callbacks); 401 params.ipc_database_id = ipc_database_id; 402 params.transaction_id = transaction_id; 403 params.object_store_id = object_store_id; 404 params.index_id = index_id; 405 params.key_range = key_range; 406 params.direction = direction; 407 params.key_only = key_only; 408 params.task_type = task_type; 409 Send(new IndexedDBHostMsg_DatabaseOpenCursor(params)); 410 411 DCHECK(cursor_transaction_ids_.find(params.ipc_callbacks_id) == 412 cursor_transaction_ids_.end()); 413 cursor_transaction_ids_[params.ipc_callbacks_id] = transaction_id; 414 } 415 416 void IndexedDBDispatcher::RequestIDBDatabaseCount( 417 int32 ipc_database_id, 418 int64 transaction_id, 419 int64 object_store_id, 420 int64 index_id, 421 const IndexedDBKeyRange& key_range, 422 WebIDBCallbacks* callbacks) { 423 ResetCursorPrefetchCaches(transaction_id, kAllCursors); 424 IndexedDBHostMsg_DatabaseCount_Params params; 425 init_params(¶ms, callbacks); 426 params.ipc_database_id = ipc_database_id; 427 params.transaction_id = transaction_id; 428 params.object_store_id = object_store_id; 429 params.index_id = index_id; 430 params.key_range = key_range; 431 Send(new IndexedDBHostMsg_DatabaseCount(params)); 432 } 433 434 void IndexedDBDispatcher::RequestIDBDatabaseDeleteRange( 435 int32 ipc_database_id, 436 int64 transaction_id, 437 int64 object_store_id, 438 const IndexedDBKeyRange& key_range, 439 WebIDBCallbacks* callbacks) { 440 ResetCursorPrefetchCaches(transaction_id, kAllCursors); 441 IndexedDBHostMsg_DatabaseDeleteRange_Params params; 442 init_params(¶ms, callbacks); 443 params.ipc_database_id = ipc_database_id; 444 params.transaction_id = transaction_id; 445 params.object_store_id = object_store_id; 446 params.key_range = key_range; 447 Send(new IndexedDBHostMsg_DatabaseDeleteRange(params)); 448 } 449 450 void IndexedDBDispatcher::RequestIDBDatabaseClear( 451 int32 ipc_database_id, 452 int64 transaction_id, 453 int64 object_store_id, 454 WebIDBCallbacks* callbacks_ptr) { 455 ResetCursorPrefetchCaches(transaction_id, kAllCursors); 456 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 457 int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release()); 458 Send(new IndexedDBHostMsg_DatabaseClear(CurrentWorkerId(), 459 ipc_callbacks_id, 460 ipc_database_id, 461 transaction_id, 462 object_store_id)); 463 } 464 465 void IndexedDBDispatcher::CursorDestroyed(int32 ipc_cursor_id) { 466 cursors_.erase(ipc_cursor_id); 467 } 468 469 void IndexedDBDispatcher::DatabaseDestroyed(int32 ipc_database_id) { 470 DCHECK_EQ(databases_.count(ipc_database_id), 1u); 471 databases_.erase(ipc_database_id); 472 } 473 474 void IndexedDBDispatcher::OnSuccessIDBDatabase( 475 int32 ipc_thread_id, 476 int32 ipc_callbacks_id, 477 int32 ipc_database_callbacks_id, 478 int32 ipc_object_id, 479 const IndexedDBDatabaseMetadata& idb_metadata) { 480 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 481 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 482 if (!callbacks) 483 return; 484 WebIDBMetadata metadata(ConvertMetadata(idb_metadata)); 485 // If an upgrade was performed, count will be non-zero. 486 WebIDBDatabase* database = NULL; 487 488 // Back-end will send kNoDatabase if it was already sent in OnUpgradeNeeded. 489 // May already be deleted and removed from the table, but do not recreate.. 490 if (ipc_object_id != kNoDatabase) { 491 DCHECK(!databases_.count(ipc_object_id)); 492 database = databases_[ipc_object_id] = new WebIDBDatabaseImpl( 493 ipc_object_id, ipc_database_callbacks_id, thread_safe_sender_.get()); 494 } 495 496 callbacks->onSuccess(database, metadata); 497 pending_callbacks_.Remove(ipc_callbacks_id); 498 } 499 500 void IndexedDBDispatcher::OnSuccessIndexedDBKey(int32 ipc_thread_id, 501 int32 ipc_callbacks_id, 502 const IndexedDBKey& key) { 503 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 504 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 505 if (!callbacks) 506 return; 507 callbacks->onSuccess(WebIDBKeyBuilder::Build(key)); 508 pending_callbacks_.Remove(ipc_callbacks_id); 509 } 510 511 void IndexedDBDispatcher::OnSuccessStringList( 512 int32 ipc_thread_id, 513 int32 ipc_callbacks_id, 514 const std::vector<base::string16>& value) { 515 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 516 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 517 if (!callbacks) 518 return; 519 callbacks->onSuccess(WebVector<WebString>(value)); 520 pending_callbacks_.Remove(ipc_callbacks_id); 521 } 522 523 static void PrepareWebValueAndBlobInfo( 524 const std::string& value, 525 const std::vector<IndexedDBMsg_BlobOrFileInfo>& blob_info, 526 WebData* web_value, 527 blink::WebVector<WebBlobInfo>* web_blob_info) { 528 529 if (value.empty()) 530 return; 531 532 web_value->assign(&*value.begin(), value.size()); 533 blink::WebVector<WebBlobInfo> local_blob_info(blob_info.size()); 534 for (size_t i = 0; i < blob_info.size(); ++i) { 535 const IndexedDBMsg_BlobOrFileInfo& info = blob_info[i]; 536 if (info.is_file) { 537 local_blob_info[i] = WebBlobInfo(WebString::fromUTF8(info.uuid.c_str()), 538 info.file_path, 539 info.file_name, 540 info.mime_type, 541 info.last_modified, 542 info.size); 543 } else { 544 local_blob_info[i] = WebBlobInfo( 545 WebString::fromUTF8(info.uuid.c_str()), info.mime_type, info.size); 546 } 547 } 548 web_blob_info->swap(local_blob_info); 549 } 550 551 void IndexedDBDispatcher::OnSuccessValue( 552 const IndexedDBMsg_CallbacksSuccessValue_Params& params) { 553 DCHECK_EQ(params.ipc_thread_id, CurrentWorkerId()); 554 WebIDBCallbacks* callbacks = 555 pending_callbacks_.Lookup(params.ipc_callbacks_id); 556 if (!callbacks) 557 return; 558 WebData web_value; 559 WebVector<WebBlobInfo> web_blob_info; 560 PrepareWebValueAndBlobInfo( 561 params.value, params.blob_or_file_info, &web_value, &web_blob_info); 562 callbacks->onSuccess(web_value, web_blob_info); 563 pending_callbacks_.Remove(params.ipc_callbacks_id); 564 cursor_transaction_ids_.erase(params.ipc_callbacks_id); 565 } 566 567 void IndexedDBDispatcher::OnSuccessValueWithKey( 568 const IndexedDBMsg_CallbacksSuccessValueWithKey_Params& params) { 569 DCHECK_EQ(params.ipc_thread_id, CurrentWorkerId()); 570 WebIDBCallbacks* callbacks = 571 pending_callbacks_.Lookup(params.ipc_callbacks_id); 572 if (!callbacks) 573 return; 574 WebData web_value; 575 WebVector<WebBlobInfo> web_blob_info; 576 PrepareWebValueAndBlobInfo( 577 params.value, params.blob_or_file_info, &web_value, &web_blob_info); 578 callbacks->onSuccess(web_value, 579 web_blob_info, 580 WebIDBKeyBuilder::Build(params.primary_key), 581 WebIDBKeyPathBuilder::Build(params.key_path)); 582 pending_callbacks_.Remove(params.ipc_callbacks_id); 583 } 584 585 void IndexedDBDispatcher::OnSuccessInteger(int32 ipc_thread_id, 586 int32 ipc_callbacks_id, 587 int64 value) { 588 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 589 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 590 if (!callbacks) 591 return; 592 callbacks->onSuccess(value); 593 pending_callbacks_.Remove(ipc_callbacks_id); 594 } 595 596 void IndexedDBDispatcher::OnSuccessUndefined(int32 ipc_thread_id, 597 int32 ipc_callbacks_id) { 598 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 599 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 600 if (!callbacks) 601 return; 602 callbacks->onSuccess(); 603 pending_callbacks_.Remove(ipc_callbacks_id); 604 } 605 606 void IndexedDBDispatcher::OnSuccessOpenCursor( 607 const IndexedDBMsg_CallbacksSuccessIDBCursor_Params& p) { 608 DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId()); 609 int32 ipc_callbacks_id = p.ipc_callbacks_id; 610 int32 ipc_object_id = p.ipc_cursor_id; 611 const IndexedDBKey& key = p.key; 612 const IndexedDBKey& primary_key = p.primary_key; 613 WebData web_value; 614 WebVector<WebBlobInfo> web_blob_info; 615 PrepareWebValueAndBlobInfo( 616 p.value, p.blob_or_file_info, &web_value, &web_blob_info); 617 618 DCHECK(cursor_transaction_ids_.find(ipc_callbacks_id) != 619 cursor_transaction_ids_.end()); 620 int64 transaction_id = cursor_transaction_ids_[ipc_callbacks_id]; 621 cursor_transaction_ids_.erase(ipc_callbacks_id); 622 623 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 624 if (!callbacks) 625 return; 626 627 WebIDBCursorImpl* cursor = new WebIDBCursorImpl( 628 ipc_object_id, transaction_id, thread_safe_sender_.get()); 629 cursors_[ipc_object_id] = cursor; 630 callbacks->onSuccess(cursor, 631 WebIDBKeyBuilder::Build(key), 632 WebIDBKeyBuilder::Build(primary_key), 633 web_value, 634 web_blob_info); 635 636 pending_callbacks_.Remove(ipc_callbacks_id); 637 } 638 639 void IndexedDBDispatcher::OnSuccessCursorContinue( 640 const IndexedDBMsg_CallbacksSuccessCursorContinue_Params& p) { 641 DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId()); 642 int32 ipc_callbacks_id = p.ipc_callbacks_id; 643 int32 ipc_cursor_id = p.ipc_cursor_id; 644 const IndexedDBKey& key = p.key; 645 const IndexedDBKey& primary_key = p.primary_key; 646 const std::string& value = p.value; 647 648 if (cursors_.find(ipc_cursor_id) == cursors_.end()) 649 return; 650 651 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 652 if (!callbacks) 653 return; 654 655 WebData web_value; 656 WebVector<WebBlobInfo> web_blob_info; 657 PrepareWebValueAndBlobInfo( 658 value, p.blob_or_file_info, &web_value, &web_blob_info); 659 callbacks->onSuccess(WebIDBKeyBuilder::Build(key), 660 WebIDBKeyBuilder::Build(primary_key), 661 web_value, 662 web_blob_info); 663 664 pending_callbacks_.Remove(ipc_callbacks_id); 665 } 666 667 void IndexedDBDispatcher::OnSuccessCursorPrefetch( 668 const IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params& p) { 669 DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId()); 670 int32 ipc_callbacks_id = p.ipc_callbacks_id; 671 int32 ipc_cursor_id = p.ipc_cursor_id; 672 const std::vector<IndexedDBKey>& keys = p.keys; 673 const std::vector<IndexedDBKey>& primary_keys = p.primary_keys; 674 std::vector<WebData> values(p.values.size()); 675 DCHECK_EQ(p.values.size(), p.blob_or_file_infos.size()); 676 std::vector<WebVector<WebBlobInfo> > blob_infos(p.blob_or_file_infos.size()); 677 for (size_t i = 0; i < p.values.size(); ++i) { 678 PrepareWebValueAndBlobInfo( 679 p.values[i], p.blob_or_file_infos[i], &values[i], &blob_infos[i]); 680 } 681 std::map<int32, WebIDBCursorImpl*>::const_iterator cur_iter = 682 cursors_.find(ipc_cursor_id); 683 if (cur_iter == cursors_.end()) 684 return; 685 686 cur_iter->second->SetPrefetchData(keys, primary_keys, values, blob_infos); 687 688 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 689 DCHECK(callbacks); 690 cur_iter->second->CachedContinue(callbacks); 691 pending_callbacks_.Remove(ipc_callbacks_id); 692 } 693 694 void IndexedDBDispatcher::OnIntBlocked(int32 ipc_thread_id, 695 int32 ipc_callbacks_id, 696 int64 existing_version) { 697 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 698 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 699 DCHECK(callbacks); 700 callbacks->onBlocked(existing_version); 701 } 702 703 void IndexedDBDispatcher::OnUpgradeNeeded( 704 const IndexedDBMsg_CallbacksUpgradeNeeded_Params& p) { 705 DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId()); 706 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(p.ipc_callbacks_id); 707 DCHECK(callbacks); 708 WebIDBMetadata metadata(ConvertMetadata(p.idb_metadata)); 709 DCHECK(!databases_.count(p.ipc_database_id)); 710 databases_[p.ipc_database_id] = 711 new WebIDBDatabaseImpl(p.ipc_database_id, 712 p.ipc_database_callbacks_id, 713 thread_safe_sender_.get()); 714 callbacks->onUpgradeNeeded( 715 p.old_version, 716 databases_[p.ipc_database_id], 717 metadata, 718 static_cast<blink::WebIDBDataLoss>(p.data_loss), 719 WebString::fromUTF8(p.data_loss_message)); 720 } 721 722 void IndexedDBDispatcher::OnError(int32 ipc_thread_id, 723 int32 ipc_callbacks_id, 724 int code, 725 const base::string16& message) { 726 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 727 WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id); 728 if (!callbacks) 729 return; 730 if (message.empty()) 731 callbacks->onError(WebIDBDatabaseError(code)); 732 else 733 callbacks->onError(WebIDBDatabaseError(code, message)); 734 pending_callbacks_.Remove(ipc_callbacks_id); 735 cursor_transaction_ids_.erase(ipc_callbacks_id); 736 } 737 738 void IndexedDBDispatcher::OnAbort(int32 ipc_thread_id, 739 int32 ipc_database_callbacks_id, 740 int64 transaction_id, 741 int code, 742 const base::string16& message) { 743 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 744 WebIDBDatabaseCallbacks* callbacks = 745 pending_database_callbacks_.Lookup(ipc_database_callbacks_id); 746 if (!callbacks) 747 return; 748 if (message.empty()) 749 callbacks->onAbort(transaction_id, WebIDBDatabaseError(code)); 750 else 751 callbacks->onAbort(transaction_id, WebIDBDatabaseError(code, message)); 752 } 753 754 void IndexedDBDispatcher::OnComplete(int32 ipc_thread_id, 755 int32 ipc_database_callbacks_id, 756 int64 transaction_id) { 757 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 758 WebIDBDatabaseCallbacks* callbacks = 759 pending_database_callbacks_.Lookup(ipc_database_callbacks_id); 760 if (!callbacks) 761 return; 762 callbacks->onComplete(transaction_id); 763 } 764 765 void IndexedDBDispatcher::OnForcedClose(int32 ipc_thread_id, 766 int32 ipc_database_callbacks_id) { 767 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 768 WebIDBDatabaseCallbacks* callbacks = 769 pending_database_callbacks_.Lookup(ipc_database_callbacks_id); 770 if (!callbacks) 771 return; 772 callbacks->onForcedClose(); 773 } 774 775 void IndexedDBDispatcher::OnIntVersionChange(int32 ipc_thread_id, 776 int32 ipc_database_callbacks_id, 777 int64 old_version, 778 int64 new_version) { 779 DCHECK_EQ(ipc_thread_id, CurrentWorkerId()); 780 WebIDBDatabaseCallbacks* callbacks = 781 pending_database_callbacks_.Lookup(ipc_database_callbacks_id); 782 // callbacks would be NULL if a versionchange event is received after close 783 // has been called. 784 if (!callbacks) 785 return; 786 callbacks->onVersionChange(old_version, new_version); 787 } 788 789 void IndexedDBDispatcher::ResetCursorPrefetchCaches( 790 int64 transaction_id, 791 int32 ipc_exception_cursor_id) { 792 typedef std::map<int32, WebIDBCursorImpl*>::iterator Iterator; 793 for (Iterator i = cursors_.begin(); i != cursors_.end(); ++i) { 794 if (i->first == ipc_exception_cursor_id || 795 i->second->transaction_id() != transaction_id) 796 continue; 797 i->second->ResetPrefetchCache(); 798 } 799 } 800 801 } // namespace content 802