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(¶ms, callbacks);
314 params.ipc_database_id = ipc_database_id;
315 params.transaction_id = transaction_id;
316 params.object_store_id = object_store_id;
317 params.index_id = index_id;
318 params.key_range = key_range;
319 params.key_only = key_only;
320 Send(new IndexedDBHostMsg_DatabaseGet(params));
321 }
322
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(¶ms, callbacks);
349 params.ipc_database_id = ipc_database_id;
350 params.transaction_id = transaction_id;
351 params.object_store_id = object_store_id;
352
353 params.value.assign(value.data(), value.data() + value.size());
354 params.key = key;
355 params.put_mode = put_mode;
356
357 DCHECK_EQ(index_ids.size(), index_keys.size());
358 params.index_keys.resize(index_ids.size());
359 for (size_t i = 0, len = index_ids.size(); i < len; ++i) {
360 params.index_keys[i].first = index_ids[i];
361 params.index_keys[i].second.resize(index_keys[i].size());
362 for (size_t j = 0; j < index_keys[i].size(); ++j) {
363 params.index_keys[i].second[j] =
364 IndexedDBKey(IndexedDBKeyBuilder::Build(index_keys[i][j]));
365 }
366 }
367
368 params.blob_or_file_info.resize(web_blob_info.size());
369 for (size_t i = 0; i < web_blob_info.size(); ++i) {
370 const WebBlobInfo& info = web_blob_info[i];
371 IndexedDBMsg_BlobOrFileInfo& blob_or_file_info =
372 params.blob_or_file_info[i];
373 blob_or_file_info.is_file = info.isFile();
374 if (info.isFile()) {
375 blob_or_file_info.file_path = info.filePath();
376 blob_or_file_info.file_name = info.fileName();
377 blob_or_file_info.last_modified = info.lastModified();
378 }
379 blob_or_file_info.size = info.size();
380 blob_or_file_info.uuid = info.uuid().latin1();
381 DCHECK(blob_or_file_info.uuid.size());
382 blob_or_file_info.mime_type = info.type();
383 }
384
385 Send(new IndexedDBHostMsg_DatabasePut(params));
386 }
387
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(¶ms, callbacks);
401 params.ipc_database_id = ipc_database_id;
402 params.transaction_id = transaction_id;
403 params.object_store_id = object_store_id;
404 params.index_id = index_id;
405 params.key_range = key_range;
406 params.direction = direction;
407 params.key_only = key_only;
408 params.task_type = task_type;
409 Send(new IndexedDBHostMsg_DatabaseOpenCursor(params));
410
411 DCHECK(cursor_transaction_ids_.find(params.ipc_callbacks_id) ==
412 cursor_transaction_ids_.end());
413 cursor_transaction_ids_[params.ipc_callbacks_id] = transaction_id;
414 }
415
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(¶ms, callbacks);
426 params.ipc_database_id = ipc_database_id;
427 params.transaction_id = transaction_id;
428 params.object_store_id = object_store_id;
429 params.index_id = index_id;
430 params.key_range = key_range;
431 Send(new IndexedDBHostMsg_DatabaseCount(params));
432 }
433
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(¶ms, callbacks);
443 params.ipc_database_id = ipc_database_id;
444 params.transaction_id = transaction_id;
445 params.object_store_id = object_store_id;
446 params.key_range = key_range;
447 Send(new IndexedDBHostMsg_DatabaseDeleteRange(params));
448 }
449
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