• Home
  • History
  • Annotate
  • 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 
NotifyIDBDatabaseVersionChangeIgnored(int32 ipc_database_id)281 void IndexedDBDispatcher::NotifyIDBDatabaseVersionChangeIgnored(
282     int32 ipc_database_id) {
283   Send(new IndexedDBHostMsg_DatabaseVersionChangeIgnored(ipc_database_id));
284 }
285 
RequestIDBDatabaseCreateTransaction(int32 ipc_database_id,int64 transaction_id,WebIDBDatabaseCallbacks * database_callbacks_ptr,WebVector<long long> object_store_ids,blink::WebIDBTransactionMode mode)286 void IndexedDBDispatcher::RequestIDBDatabaseCreateTransaction(
287     int32 ipc_database_id,
288     int64 transaction_id,
289     WebIDBDatabaseCallbacks* database_callbacks_ptr,
290     WebVector<long long> object_store_ids,
291     blink::WebIDBTransactionMode mode) {
292   scoped_ptr<WebIDBDatabaseCallbacks> database_callbacks(
293       database_callbacks_ptr);
294   IndexedDBHostMsg_DatabaseCreateTransaction_Params params;
295   params.ipc_thread_id = CurrentWorkerId();
296   params.ipc_database_id = ipc_database_id;
297   params.transaction_id = transaction_id;
298   params.ipc_database_callbacks_id =
299       pending_database_callbacks_.Add(database_callbacks.release());
300   params.object_store_ids
301       .assign(object_store_ids.data(),
302               object_store_ids.data() + object_store_ids.size());
303   params.mode = mode;
304 
305   Send(new IndexedDBHostMsg_DatabaseCreateTransaction(params));
306 }
307 
RequestIDBDatabaseGet(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,int64 index_id,const IndexedDBKeyRange & key_range,bool key_only,WebIDBCallbacks * callbacks)308 void IndexedDBDispatcher::RequestIDBDatabaseGet(
309     int32 ipc_database_id,
310     int64 transaction_id,
311     int64 object_store_id,
312     int64 index_id,
313     const IndexedDBKeyRange& key_range,
314     bool key_only,
315     WebIDBCallbacks* callbacks) {
316   ResetCursorPrefetchCaches(transaction_id, kAllCursors);
317   IndexedDBHostMsg_DatabaseGet_Params params;
318   init_params(&params, callbacks);
319   params.ipc_database_id = ipc_database_id;
320   params.transaction_id = transaction_id;
321   params.object_store_id = object_store_id;
322   params.index_id = index_id;
323   params.key_range = key_range;
324   params.key_only = key_only;
325   Send(new IndexedDBHostMsg_DatabaseGet(params));
326 }
327 
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,blink::WebIDBPutMode put_mode,WebIDBCallbacks * callbacks,const WebVector<long long> & index_ids,const WebVector<WebVector<WebIDBKey>> & index_keys)328 void IndexedDBDispatcher::RequestIDBDatabasePut(
329     int32 ipc_database_id,
330     int64 transaction_id,
331     int64 object_store_id,
332     const WebData& value,
333     const blink::WebVector<WebBlobInfo>& web_blob_info,
334     const IndexedDBKey& key,
335     blink::WebIDBPutMode put_mode,
336     WebIDBCallbacks* callbacks,
337     const WebVector<long long>& index_ids,
338     const WebVector<WebVector<WebIDBKey> >& index_keys) {
339   if (value.size() + key.size_estimate() > kMaxIDBValueSizeInBytes) {
340     callbacks->onError(WebIDBDatabaseError(
341         blink::WebIDBDatabaseExceptionUnknownError,
342         WebString::fromUTF8(base::StringPrintf(
343             "The serialized value is too large"
344             " (size=%" PRIuS " bytes, max=%" PRIuS " bytes).",
345             value.size(),
346             kMaxIDBValueSizeInBytes).c_str())));
347     return;
348   }
349 
350   ResetCursorPrefetchCaches(transaction_id, kAllCursors);
351   IndexedDBHostMsg_DatabasePut_Params params;
352   init_params(&params, callbacks);
353   params.ipc_database_id = ipc_database_id;
354   params.transaction_id = transaction_id;
355   params.object_store_id = object_store_id;
356 
357   params.value.assign(value.data(), value.data() + value.size());
358   params.key = key;
359   params.put_mode = put_mode;
360 
361   DCHECK_EQ(index_ids.size(), index_keys.size());
362   params.index_keys.resize(index_ids.size());
363   for (size_t i = 0, len = index_ids.size(); i < len; ++i) {
364     params.index_keys[i].first = index_ids[i];
365     params.index_keys[i].second.resize(index_keys[i].size());
366     for (size_t j = 0; j < index_keys[i].size(); ++j) {
367       params.index_keys[i].second[j] =
368           IndexedDBKey(IndexedDBKeyBuilder::Build(index_keys[i][j]));
369     }
370   }
371 
372   params.blob_or_file_info.resize(web_blob_info.size());
373   for (size_t i = 0; i < web_blob_info.size(); ++i) {
374     const WebBlobInfo& info = web_blob_info[i];
375     IndexedDBMsg_BlobOrFileInfo& blob_or_file_info =
376         params.blob_or_file_info[i];
377     blob_or_file_info.is_file = info.isFile();
378     if (info.isFile()) {
379       blob_or_file_info.file_path = info.filePath();
380       blob_or_file_info.file_name = info.fileName();
381       blob_or_file_info.last_modified = info.lastModified();
382     }
383     blob_or_file_info.size = info.size();
384     blob_or_file_info.uuid = info.uuid().latin1();
385     DCHECK(blob_or_file_info.uuid.size());
386     blob_or_file_info.mime_type = info.type();
387   }
388 
389   Send(new IndexedDBHostMsg_DatabasePut(params));
390 }
391 
RequestIDBDatabaseOpenCursor(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,int64 index_id,const IndexedDBKeyRange & key_range,blink::WebIDBCursorDirection direction,bool key_only,blink::WebIDBTaskType task_type,WebIDBCallbacks * callbacks)392 void IndexedDBDispatcher::RequestIDBDatabaseOpenCursor(
393     int32 ipc_database_id,
394     int64 transaction_id,
395     int64 object_store_id,
396     int64 index_id,
397     const IndexedDBKeyRange& key_range,
398     blink::WebIDBCursorDirection direction,
399     bool key_only,
400     blink::WebIDBTaskType task_type,
401     WebIDBCallbacks* callbacks) {
402   ResetCursorPrefetchCaches(transaction_id, kAllCursors);
403   IndexedDBHostMsg_DatabaseOpenCursor_Params params;
404   init_params(&params, callbacks);
405   params.ipc_database_id = ipc_database_id;
406   params.transaction_id = transaction_id;
407   params.object_store_id = object_store_id;
408   params.index_id = index_id;
409   params.key_range = key_range;
410   params.direction = direction;
411   params.key_only = key_only;
412   params.task_type = task_type;
413   Send(new IndexedDBHostMsg_DatabaseOpenCursor(params));
414 
415   DCHECK(cursor_transaction_ids_.find(params.ipc_callbacks_id) ==
416          cursor_transaction_ids_.end());
417   cursor_transaction_ids_[params.ipc_callbacks_id] = transaction_id;
418 }
419 
RequestIDBDatabaseCount(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,int64 index_id,const IndexedDBKeyRange & key_range,WebIDBCallbacks * callbacks)420 void IndexedDBDispatcher::RequestIDBDatabaseCount(
421     int32 ipc_database_id,
422     int64 transaction_id,
423     int64 object_store_id,
424     int64 index_id,
425     const IndexedDBKeyRange& key_range,
426     WebIDBCallbacks* callbacks) {
427   ResetCursorPrefetchCaches(transaction_id, kAllCursors);
428   IndexedDBHostMsg_DatabaseCount_Params params;
429   init_params(&params, callbacks);
430   params.ipc_database_id = ipc_database_id;
431   params.transaction_id = transaction_id;
432   params.object_store_id = object_store_id;
433   params.index_id = index_id;
434   params.key_range = key_range;
435   Send(new IndexedDBHostMsg_DatabaseCount(params));
436 }
437 
RequestIDBDatabaseDeleteRange(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,const IndexedDBKeyRange & key_range,WebIDBCallbacks * callbacks)438 void IndexedDBDispatcher::RequestIDBDatabaseDeleteRange(
439     int32 ipc_database_id,
440     int64 transaction_id,
441     int64 object_store_id,
442     const IndexedDBKeyRange& key_range,
443     WebIDBCallbacks* callbacks) {
444   ResetCursorPrefetchCaches(transaction_id, kAllCursors);
445   IndexedDBHostMsg_DatabaseDeleteRange_Params params;
446   init_params(&params, callbacks);
447   params.ipc_database_id = ipc_database_id;
448   params.transaction_id = transaction_id;
449   params.object_store_id = object_store_id;
450   params.key_range = key_range;
451   Send(new IndexedDBHostMsg_DatabaseDeleteRange(params));
452 }
453 
RequestIDBDatabaseClear(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,WebIDBCallbacks * callbacks_ptr)454 void IndexedDBDispatcher::RequestIDBDatabaseClear(
455     int32 ipc_database_id,
456     int64 transaction_id,
457     int64 object_store_id,
458     WebIDBCallbacks* callbacks_ptr) {
459   ResetCursorPrefetchCaches(transaction_id, kAllCursors);
460   scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
461   int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
462   Send(new IndexedDBHostMsg_DatabaseClear(CurrentWorkerId(),
463                                           ipc_callbacks_id,
464                                           ipc_database_id,
465                                           transaction_id,
466                                           object_store_id));
467 }
468 
CursorDestroyed(int32 ipc_cursor_id)469 void IndexedDBDispatcher::CursorDestroyed(int32 ipc_cursor_id) {
470   cursors_.erase(ipc_cursor_id);
471 }
472 
DatabaseDestroyed(int32 ipc_database_id)473 void IndexedDBDispatcher::DatabaseDestroyed(int32 ipc_database_id) {
474   DCHECK_EQ(databases_.count(ipc_database_id), 1u);
475   databases_.erase(ipc_database_id);
476 }
477 
OnSuccessIDBDatabase(int32 ipc_thread_id,int32 ipc_callbacks_id,int32 ipc_database_callbacks_id,int32 ipc_object_id,const IndexedDBDatabaseMetadata & idb_metadata)478 void IndexedDBDispatcher::OnSuccessIDBDatabase(
479     int32 ipc_thread_id,
480     int32 ipc_callbacks_id,
481     int32 ipc_database_callbacks_id,
482     int32 ipc_object_id,
483     const IndexedDBDatabaseMetadata& idb_metadata) {
484   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
485   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
486   if (!callbacks)
487     return;
488   WebIDBMetadata metadata(ConvertMetadata(idb_metadata));
489   // If an upgrade was performed, count will be non-zero.
490   WebIDBDatabase* database = NULL;
491 
492   // Back-end will send kNoDatabase if it was already sent in OnUpgradeNeeded.
493   // May already be deleted and removed from the table, but do not recreate..
494   if (ipc_object_id != kNoDatabase) {
495     DCHECK(!databases_.count(ipc_object_id));
496     database = databases_[ipc_object_id] = new WebIDBDatabaseImpl(
497         ipc_object_id, ipc_database_callbacks_id, thread_safe_sender_.get());
498   }
499 
500   callbacks->onSuccess(database, metadata);
501   pending_callbacks_.Remove(ipc_callbacks_id);
502 }
503 
OnSuccessIndexedDBKey(int32 ipc_thread_id,int32 ipc_callbacks_id,const IndexedDBKey & key)504 void IndexedDBDispatcher::OnSuccessIndexedDBKey(int32 ipc_thread_id,
505                                                 int32 ipc_callbacks_id,
506                                                 const IndexedDBKey& key) {
507   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
508   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
509   if (!callbacks)
510     return;
511   callbacks->onSuccess(WebIDBKeyBuilder::Build(key));
512   pending_callbacks_.Remove(ipc_callbacks_id);
513 }
514 
OnSuccessStringList(int32 ipc_thread_id,int32 ipc_callbacks_id,const std::vector<base::string16> & value)515 void IndexedDBDispatcher::OnSuccessStringList(
516     int32 ipc_thread_id,
517     int32 ipc_callbacks_id,
518     const std::vector<base::string16>& value) {
519   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
520   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
521   if (!callbacks)
522     return;
523   callbacks->onSuccess(WebVector<WebString>(value));
524   pending_callbacks_.Remove(ipc_callbacks_id);
525 }
526 
PrepareWebValueAndBlobInfo(const std::string & value,const std::vector<IndexedDBMsg_BlobOrFileInfo> & blob_info,WebData * web_value,blink::WebVector<WebBlobInfo> * web_blob_info)527 static void PrepareWebValueAndBlobInfo(
528     const std::string& value,
529     const std::vector<IndexedDBMsg_BlobOrFileInfo>& blob_info,
530     WebData* web_value,
531     blink::WebVector<WebBlobInfo>* web_blob_info) {
532 
533   if (value.empty())
534     return;
535 
536   web_value->assign(&*value.begin(), value.size());
537   blink::WebVector<WebBlobInfo> local_blob_info(blob_info.size());
538   for (size_t i = 0; i < blob_info.size(); ++i) {
539     const IndexedDBMsg_BlobOrFileInfo& info = blob_info[i];
540     if (info.is_file) {
541       local_blob_info[i] = WebBlobInfo(WebString::fromUTF8(info.uuid.c_str()),
542                                        info.file_path,
543                                        info.file_name,
544                                        info.mime_type,
545                                        info.last_modified,
546                                        info.size);
547     } else {
548       local_blob_info[i] = WebBlobInfo(
549           WebString::fromUTF8(info.uuid.c_str()), info.mime_type, info.size);
550     }
551   }
552   web_blob_info->swap(local_blob_info);
553 }
554 
OnSuccessValue(const IndexedDBMsg_CallbacksSuccessValue_Params & params)555 void IndexedDBDispatcher::OnSuccessValue(
556     const IndexedDBMsg_CallbacksSuccessValue_Params& params) {
557   DCHECK_EQ(params.ipc_thread_id, CurrentWorkerId());
558   WebIDBCallbacks* callbacks =
559       pending_callbacks_.Lookup(params.ipc_callbacks_id);
560   if (!callbacks)
561     return;
562   WebData web_value;
563   WebVector<WebBlobInfo> web_blob_info;
564   PrepareWebValueAndBlobInfo(
565       params.value, params.blob_or_file_info, &web_value, &web_blob_info);
566   callbacks->onSuccess(web_value, web_blob_info);
567   pending_callbacks_.Remove(params.ipc_callbacks_id);
568   cursor_transaction_ids_.erase(params.ipc_callbacks_id);
569 }
570 
OnSuccessValueWithKey(const IndexedDBMsg_CallbacksSuccessValueWithKey_Params & params)571 void IndexedDBDispatcher::OnSuccessValueWithKey(
572     const IndexedDBMsg_CallbacksSuccessValueWithKey_Params& params) {
573   DCHECK_EQ(params.ipc_thread_id, CurrentWorkerId());
574   WebIDBCallbacks* callbacks =
575       pending_callbacks_.Lookup(params.ipc_callbacks_id);
576   if (!callbacks)
577     return;
578   WebData web_value;
579   WebVector<WebBlobInfo> web_blob_info;
580   PrepareWebValueAndBlobInfo(
581       params.value, params.blob_or_file_info, &web_value, &web_blob_info);
582   callbacks->onSuccess(web_value,
583                        web_blob_info,
584                        WebIDBKeyBuilder::Build(params.primary_key),
585                        WebIDBKeyPathBuilder::Build(params.key_path));
586   pending_callbacks_.Remove(params.ipc_callbacks_id);
587 }
588 
OnSuccessInteger(int32 ipc_thread_id,int32 ipc_callbacks_id,int64 value)589 void IndexedDBDispatcher::OnSuccessInteger(int32 ipc_thread_id,
590                                            int32 ipc_callbacks_id,
591                                            int64 value) {
592   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
593   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
594   if (!callbacks)
595     return;
596   callbacks->onSuccess(value);
597   pending_callbacks_.Remove(ipc_callbacks_id);
598 }
599 
OnSuccessUndefined(int32 ipc_thread_id,int32 ipc_callbacks_id)600 void IndexedDBDispatcher::OnSuccessUndefined(int32 ipc_thread_id,
601                                              int32 ipc_callbacks_id) {
602   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
603   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
604   if (!callbacks)
605     return;
606   callbacks->onSuccess();
607   pending_callbacks_.Remove(ipc_callbacks_id);
608 }
609 
OnSuccessOpenCursor(const IndexedDBMsg_CallbacksSuccessIDBCursor_Params & p)610 void IndexedDBDispatcher::OnSuccessOpenCursor(
611     const IndexedDBMsg_CallbacksSuccessIDBCursor_Params& p) {
612   DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
613   int32 ipc_callbacks_id = p.ipc_callbacks_id;
614   int32 ipc_object_id = p.ipc_cursor_id;
615   const IndexedDBKey& key = p.key;
616   const IndexedDBKey& primary_key = p.primary_key;
617   WebData web_value;
618   WebVector<WebBlobInfo> web_blob_info;
619   PrepareWebValueAndBlobInfo(
620       p.value, p.blob_or_file_info, &web_value, &web_blob_info);
621 
622   DCHECK(cursor_transaction_ids_.find(ipc_callbacks_id) !=
623          cursor_transaction_ids_.end());
624   int64 transaction_id = cursor_transaction_ids_[ipc_callbacks_id];
625   cursor_transaction_ids_.erase(ipc_callbacks_id);
626 
627   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
628   if (!callbacks)
629     return;
630 
631   WebIDBCursorImpl* cursor = new WebIDBCursorImpl(
632       ipc_object_id, transaction_id, thread_safe_sender_.get());
633   cursors_[ipc_object_id] = cursor;
634   callbacks->onSuccess(cursor,
635                        WebIDBKeyBuilder::Build(key),
636                        WebIDBKeyBuilder::Build(primary_key),
637                        web_value,
638                        web_blob_info);
639 
640   pending_callbacks_.Remove(ipc_callbacks_id);
641 }
642 
OnSuccessCursorContinue(const IndexedDBMsg_CallbacksSuccessCursorContinue_Params & p)643 void IndexedDBDispatcher::OnSuccessCursorContinue(
644     const IndexedDBMsg_CallbacksSuccessCursorContinue_Params& p) {
645   DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
646   int32 ipc_callbacks_id = p.ipc_callbacks_id;
647   int32 ipc_cursor_id = p.ipc_cursor_id;
648   const IndexedDBKey& key = p.key;
649   const IndexedDBKey& primary_key = p.primary_key;
650   const std::string& value = p.value;
651 
652   if (cursors_.find(ipc_cursor_id) == cursors_.end())
653     return;
654 
655   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
656   if (!callbacks)
657     return;
658 
659   WebData web_value;
660   WebVector<WebBlobInfo> web_blob_info;
661   PrepareWebValueAndBlobInfo(
662       value, p.blob_or_file_info, &web_value, &web_blob_info);
663   callbacks->onSuccess(WebIDBKeyBuilder::Build(key),
664                        WebIDBKeyBuilder::Build(primary_key),
665                        web_value,
666                        web_blob_info);
667 
668   pending_callbacks_.Remove(ipc_callbacks_id);
669 }
670 
OnSuccessCursorPrefetch(const IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params & p)671 void IndexedDBDispatcher::OnSuccessCursorPrefetch(
672     const IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params& p) {
673   DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
674   int32 ipc_callbacks_id = p.ipc_callbacks_id;
675   int32 ipc_cursor_id = p.ipc_cursor_id;
676   const std::vector<IndexedDBKey>& keys = p.keys;
677   const std::vector<IndexedDBKey>& primary_keys = p.primary_keys;
678   std::vector<WebData> values(p.values.size());
679   DCHECK_EQ(p.values.size(), p.blob_or_file_infos.size());
680   std::vector<WebVector<WebBlobInfo> > blob_infos(p.blob_or_file_infos.size());
681   for (size_t i = 0; i < p.values.size(); ++i) {
682     PrepareWebValueAndBlobInfo(
683         p.values[i], p.blob_or_file_infos[i], &values[i], &blob_infos[i]);
684   }
685   std::map<int32, WebIDBCursorImpl*>::const_iterator cur_iter =
686       cursors_.find(ipc_cursor_id);
687   if (cur_iter == cursors_.end())
688     return;
689 
690   cur_iter->second->SetPrefetchData(keys, primary_keys, values, blob_infos);
691 
692   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
693   DCHECK(callbacks);
694   cur_iter->second->CachedContinue(callbacks);
695   pending_callbacks_.Remove(ipc_callbacks_id);
696 }
697 
OnIntBlocked(int32 ipc_thread_id,int32 ipc_callbacks_id,int64 existing_version)698 void IndexedDBDispatcher::OnIntBlocked(int32 ipc_thread_id,
699                                        int32 ipc_callbacks_id,
700                                        int64 existing_version) {
701   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
702   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
703   DCHECK(callbacks);
704   callbacks->onBlocked(existing_version);
705 }
706 
OnUpgradeNeeded(const IndexedDBMsg_CallbacksUpgradeNeeded_Params & p)707 void IndexedDBDispatcher::OnUpgradeNeeded(
708     const IndexedDBMsg_CallbacksUpgradeNeeded_Params& p) {
709   DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
710   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(p.ipc_callbacks_id);
711   DCHECK(callbacks);
712   WebIDBMetadata metadata(ConvertMetadata(p.idb_metadata));
713   DCHECK(!databases_.count(p.ipc_database_id));
714   databases_[p.ipc_database_id] =
715       new WebIDBDatabaseImpl(p.ipc_database_id,
716                              p.ipc_database_callbacks_id,
717                              thread_safe_sender_.get());
718   callbacks->onUpgradeNeeded(
719       p.old_version,
720       databases_[p.ipc_database_id],
721       metadata,
722       static_cast<blink::WebIDBDataLoss>(p.data_loss),
723       WebString::fromUTF8(p.data_loss_message));
724 }
725 
OnError(int32 ipc_thread_id,int32 ipc_callbacks_id,int code,const base::string16 & message)726 void IndexedDBDispatcher::OnError(int32 ipc_thread_id,
727                                   int32 ipc_callbacks_id,
728                                   int code,
729                                   const base::string16& message) {
730   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
731   WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
732   if (!callbacks)
733     return;
734   if (message.empty())
735     callbacks->onError(WebIDBDatabaseError(code));
736   else
737     callbacks->onError(WebIDBDatabaseError(code, message));
738   pending_callbacks_.Remove(ipc_callbacks_id);
739   cursor_transaction_ids_.erase(ipc_callbacks_id);
740 }
741 
OnAbort(int32 ipc_thread_id,int32 ipc_database_callbacks_id,int64 transaction_id,int code,const base::string16 & message)742 void IndexedDBDispatcher::OnAbort(int32 ipc_thread_id,
743                                   int32 ipc_database_callbacks_id,
744                                   int64 transaction_id,
745                                   int code,
746                                   const base::string16& message) {
747   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
748   WebIDBDatabaseCallbacks* callbacks =
749       pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
750   if (!callbacks)
751     return;
752   if (message.empty())
753     callbacks->onAbort(transaction_id, WebIDBDatabaseError(code));
754   else
755     callbacks->onAbort(transaction_id, WebIDBDatabaseError(code, message));
756 }
757 
OnComplete(int32 ipc_thread_id,int32 ipc_database_callbacks_id,int64 transaction_id)758 void IndexedDBDispatcher::OnComplete(int32 ipc_thread_id,
759                                      int32 ipc_database_callbacks_id,
760                                      int64 transaction_id) {
761   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
762   WebIDBDatabaseCallbacks* callbacks =
763       pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
764   if (!callbacks)
765     return;
766   callbacks->onComplete(transaction_id);
767 }
768 
OnForcedClose(int32 ipc_thread_id,int32 ipc_database_callbacks_id)769 void IndexedDBDispatcher::OnForcedClose(int32 ipc_thread_id,
770                                         int32 ipc_database_callbacks_id) {
771   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
772   WebIDBDatabaseCallbacks* callbacks =
773       pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
774   if (!callbacks)
775     return;
776   callbacks->onForcedClose();
777 }
778 
OnIntVersionChange(int32 ipc_thread_id,int32 ipc_database_callbacks_id,int64 old_version,int64 new_version)779 void IndexedDBDispatcher::OnIntVersionChange(int32 ipc_thread_id,
780                                              int32 ipc_database_callbacks_id,
781                                              int64 old_version,
782                                              int64 new_version) {
783   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
784   WebIDBDatabaseCallbacks* callbacks =
785       pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
786   // callbacks would be NULL if a versionchange event is received after close
787   // has been called.
788   if (!callbacks)
789     return;
790   callbacks->onVersionChange(old_version, new_version);
791 }
792 
ResetCursorPrefetchCaches(int64 transaction_id,int32 ipc_exception_cursor_id)793 void IndexedDBDispatcher::ResetCursorPrefetchCaches(
794     int64 transaction_id,
795     int32 ipc_exception_cursor_id) {
796   typedef std::map<int32, WebIDBCursorImpl*>::iterator Iterator;
797   for (Iterator i = cursors_.begin(); i != cursors_.end(); ++i) {
798     if (i->first == ipc_exception_cursor_id ||
799         i->second->transaction_id() != transaction_id)
800       continue;
801     i->second->ResetPrefetchCache();
802   }
803 }
804 
805 }  // namespace content
806