• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IndexedDBDispatcher(ThreadSafeSender * thread_safe_sender)52 IndexedDBDispatcher::IndexedDBDispatcher(ThreadSafeSender* thread_safe_sender)
53     : thread_safe_sender_(thread_safe_sender) {
54   g_idb_dispatcher_tls.Pointer()->Set(this);
55 }
56 
~IndexedDBDispatcher()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 
ThreadSpecificInstance(ThreadSafeSender * thread_safe_sender)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 
OnWorkerRunLoopStopped()84 void IndexedDBDispatcher::OnWorkerRunLoopStopped() { delete this; }
85 
ConvertMetadata(const IndexedDBDatabaseMetadata & idb_metadata)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 
OnMessageReceived(const IPC::Message & msg)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 
Send(IPC::Message * msg)169 bool IndexedDBDispatcher::Send(IPC::Message* msg) {
170   return thread_safe_sender_->Send(msg);
171 }
172 
RequestIDBCursorAdvance(unsigned long count,WebIDBCallbacks * callbacks_ptr,int32 ipc_cursor_id,int64 transaction_id)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 
RequestIDBCursorContinue(const IndexedDBKey & key,const IndexedDBKey & primary_key,WebIDBCallbacks * callbacks_ptr,int32 ipc_cursor_id,int64 transaction_id)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 
RequestIDBCursorPrefetch(int n,WebIDBCallbacks * callbacks_ptr,int32 ipc_cursor_id)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 
RequestIDBCursorPrefetchReset(int used_prefetches,int unused_prefetches,int32 ipc_cursor_id)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 
RequestIDBFactoryOpen(const base::string16 & name,int64 version,int64 transaction_id,WebIDBCallbacks * callbacks_ptr,WebIDBDatabaseCallbacks * database_callbacks_ptr,const std::string & database_identifier)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 
RequestIDBFactoryGetDatabaseNames(WebIDBCallbacks * callbacks_ptr,const std::string & database_identifier)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 
RequestIDBFactoryDeleteDatabase(const base::string16 & name,WebIDBCallbacks * callbacks_ptr,const std::string & database_identifier)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 
RequestIDBDatabaseClose(int32 ipc_database_id,int32 ipc_database_callbacks_id)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 
RequestIDBDatabaseCreateTransaction(int32 ipc_database_id,int64 transaction_id,WebIDBDatabaseCallbacks * database_callbacks_ptr,WebVector<long long> object_store_ids,WebIDBDatabase::TransactionMode mode)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 
RequestIDBDatabaseGet(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,int64 index_id,const IndexedDBKeyRange & key_range,bool key_only,WebIDBCallbacks * callbacks)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 
RequestIDBDatabasePut(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,const WebData & value,const blink::WebVector<WebBlobInfo> & web_blob_info,const IndexedDBKey & key,WebIDBDatabase::PutMode put_mode,WebIDBCallbacks * callbacks,const WebVector<long long> & index_ids,const WebVector<WebVector<WebIDBKey>> & index_keys)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 
RequestIDBDatabaseOpenCursor(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,int64 index_id,const IndexedDBKeyRange & key_range,WebIDBCursor::Direction direction,bool key_only,WebIDBDatabase::TaskType task_type,WebIDBCallbacks * callbacks)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 
RequestIDBDatabaseCount(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,int64 index_id,const IndexedDBKeyRange & key_range,WebIDBCallbacks * callbacks)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 
RequestIDBDatabaseDeleteRange(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,const IndexedDBKeyRange & key_range,WebIDBCallbacks * callbacks)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 
RequestIDBDatabaseClear(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,WebIDBCallbacks * callbacks_ptr)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 
CursorDestroyed(int32 ipc_cursor_id)465 void IndexedDBDispatcher::CursorDestroyed(int32 ipc_cursor_id) {
466   cursors_.erase(ipc_cursor_id);
467 }
468 
DatabaseDestroyed(int32 ipc_database_id)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 
OnSuccessIDBDatabase(int32 ipc_thread_id,int32 ipc_callbacks_id,int32 ipc_database_callbacks_id,int32 ipc_object_id,const IndexedDBDatabaseMetadata & idb_metadata)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 
OnSuccessIndexedDBKey(int32 ipc_thread_id,int32 ipc_callbacks_id,const IndexedDBKey & key)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 
OnSuccessStringList(int32 ipc_thread_id,int32 ipc_callbacks_id,const std::vector<base::string16> & value)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 
PrepareWebValueAndBlobInfo(const std::string & value,const std::vector<IndexedDBMsg_BlobOrFileInfo> & blob_info,WebData * web_value,blink::WebVector<WebBlobInfo> * web_blob_info)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 
OnSuccessValue(const IndexedDBMsg_CallbacksSuccessValue_Params & params)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 
OnSuccessValueWithKey(const IndexedDBMsg_CallbacksSuccessValueWithKey_Params & params)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 
OnSuccessInteger(int32 ipc_thread_id,int32 ipc_callbacks_id,int64 value)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 
OnSuccessUndefined(int32 ipc_thread_id,int32 ipc_callbacks_id)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 
OnSuccessOpenCursor(const IndexedDBMsg_CallbacksSuccessIDBCursor_Params & p)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 
OnSuccessCursorContinue(const IndexedDBMsg_CallbacksSuccessCursorContinue_Params & p)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 
OnSuccessCursorPrefetch(const IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params & p)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 
OnIntBlocked(int32 ipc_thread_id,int32 ipc_callbacks_id,int64 existing_version)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 
OnUpgradeNeeded(const IndexedDBMsg_CallbacksUpgradeNeeded_Params & p)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 
OnError(int32 ipc_thread_id,int32 ipc_callbacks_id,int code,const base::string16 & message)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 
OnAbort(int32 ipc_thread_id,int32 ipc_database_callbacks_id,int64 transaction_id,int code,const base::string16 & message)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 
OnComplete(int32 ipc_thread_id,int32 ipc_database_callbacks_id,int64 transaction_id)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 
OnForcedClose(int32 ipc_thread_id,int32 ipc_database_callbacks_id)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 
OnIntVersionChange(int32 ipc_thread_id,int32 ipc_database_callbacks_id,int64 old_version,int64 new_version)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 
ResetCursorPrefetchCaches(int64 transaction_id,int32 ipc_exception_cursor_id)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