Home | History | Annotate | Download | only in indexed_db
      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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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