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
24using blink::WebBlobInfo;
25using blink::WebData;
26using blink::WebIDBCallbacks;
27using blink::WebIDBCursor;
28using blink::WebIDBDatabase;
29using blink::WebIDBDatabaseCallbacks;
30using blink::WebIDBDatabaseError;
31using blink::WebIDBKey;
32using blink::WebIDBMetadata;
33using blink::WebString;
34using blink::WebVector;
35using base::ThreadLocalPointer;
36
37namespace content {
38static base::LazyInstance<ThreadLocalPointer<IndexedDBDispatcher> >::Leaky
39    g_idb_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
40
41namespace {
42
43IndexedDBDispatcher* const kHasBeenDeleted =
44    reinterpret_cast<IndexedDBDispatcher*>(0x1);
45
46}  // unnamed namespace
47
48const size_t kMaxIDBMessageOverhead = 1024 * 1024;  // 1MB; arbitrarily chosen.
49const size_t kMaxIDBValueSizeInBytes =
50    IPC::Channel::kMaximumMessageSize - kMaxIDBMessageOverhead;
51
52IndexedDBDispatcher::IndexedDBDispatcher(ThreadSafeSender* thread_safe_sender)
53    : thread_safe_sender_(thread_safe_sender) {
54  g_idb_dispatcher_tls.Pointer()->Set(this);
55}
56
57IndexedDBDispatcher::~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
69IndexedDBDispatcher* 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
84void IndexedDBDispatcher::OnWorkerRunLoopStopped() { delete this; }
85
86WebIDBMetadata 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
129void 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
169bool IndexedDBDispatcher::Send(IPC::Message* msg) {
170  return thread_safe_sender_->Send(msg);
171}
172
173void 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
188void 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
204void 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
215void 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
222void 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
245void 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
257void 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
271void 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
281void 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
303void 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
323void 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
388void 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
416void 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
434void 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
450void 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
465void IndexedDBDispatcher::CursorDestroyed(int32 ipc_cursor_id) {
466  cursors_.erase(ipc_cursor_id);
467}
468
469void IndexedDBDispatcher::DatabaseDestroyed(int32 ipc_database_id) {
470  DCHECK_EQ(databases_.count(ipc_database_id), 1u);
471  databases_.erase(ipc_database_id);
472}
473
474void 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
500void 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
511void 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
523static 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
551void 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
567void 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
585void 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
596void 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
606void 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
639void 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
667void 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
694void 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
703void 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
722void 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
738void 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
754void 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
765void 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
775void 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
789void 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