1 // Copyright (c) 2012 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.
5 #include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/process/process.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "content/browser/indexed_db/indexed_db_callbacks.h"
13 #include "content/browser/indexed_db/indexed_db_connection.h"
14 #include "content/browser/indexed_db/indexed_db_context_impl.h"
15 #include "content/browser/indexed_db/indexed_db_cursor.h"
16 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
17 #include "content/browser/indexed_db/indexed_db_metadata.h"
18 #include "content/browser/renderer_host/render_message_filter.h"
19 #include "content/common/indexed_db/indexed_db_messages.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/user_metrics.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/result_codes.h"
24 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
26 #include "webkit/browser/database/database_util.h"
27 #include "webkit/common/database/database_identifier.h"
29 using webkit_database::DatabaseUtil;
30 using WebKit::WebIDBKey;
34 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
36 IndexedDBContextImpl* indexed_db_context)
37 : indexed_db_context_(indexed_db_context),
38 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
39 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
40 ipc_process_id_(ipc_process_id) {
41 DCHECK(indexed_db_context_);
44 IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {}
46 void IndexedDBDispatcherHost::OnChannelClosing() {
47 bool success = indexed_db_context_->TaskRunner()->PostTask(
49 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this));
52 ResetDispatcherHosts();
55 void IndexedDBDispatcherHost::OnDestruct() const {
56 // The last reference to the dispatcher may be a posted task, which would
57 // be destructed on the IndexedDB thread. Without this override, that would
58 // take the dispatcher with it. Since the dispatcher may be keeping the
59 // IndexedDBContext alive, it might be destructed to on its own thread,
60 // which is not supported. Ensure destruction runs on the IO thread instead.
61 BrowserThread::DeleteOnIOThread::Destruct(this);
64 void IndexedDBDispatcherHost::ResetDispatcherHosts() {
65 // It is important that the various *_dispatcher_host_ members are reset
66 // on the IndexedDB thread, since there might be incoming messages on that
67 // thread, and we must not reset the dispatcher hosts until after those
68 // messages are processed.
69 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
71 // Note that we explicitly separate CloseAll() from destruction of the
72 // DatabaseDispatcherHost, since CloseAll() can invoke callbacks which need to
73 // be dispatched through database_dispatcher_host_.
74 database_dispatcher_host_->CloseAll();
75 database_dispatcher_host_.reset();
76 cursor_dispatcher_host_.reset();
79 base::TaskRunner* IndexedDBDispatcherHost::OverrideTaskRunnerForMessage(
80 const IPC::Message& message) {
81 if (IPC_MESSAGE_CLASS(message) == IndexedDBMsgStart)
82 return indexed_db_context_->TaskRunner();
86 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message,
87 bool* message_was_ok) {
88 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
91 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
94 database_dispatcher_host_->OnMessageReceived(message, message_was_ok) ||
95 cursor_dispatcher_host_->OnMessageReceived(message, message_was_ok);
99 IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost, message, *message_was_ok)
100 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames,
101 OnIDBFactoryGetDatabaseNames)
102 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen)
103 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase,
104 OnIDBFactoryDeleteDatabase)
105 IPC_MESSAGE_UNHANDLED(handled = false)
106 IPC_END_MESSAGE_MAP()
111 int32 IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) {
112 if (!cursor_dispatcher_host_) {
115 return cursor_dispatcher_host_->map_.Add(cursor);
118 int32 IndexedDBDispatcherHost::Add(IndexedDBConnection* connection,
120 const GURL& origin_url) {
121 if (!database_dispatcher_host_) {
126 int32 ipc_database_id = database_dispatcher_host_->map_.Add(connection);
127 Context()->ConnectionOpened(origin_url, connection);
128 database_dispatcher_host_->database_url_map_[ipc_database_id] = origin_url;
129 return ipc_database_id;
132 void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id,
134 if (!database_dispatcher_host_)
136 database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url;
139 int64 IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id) {
140 // Inject the renderer process id into the transaction id, to
141 // uniquely identify this transaction, and effectively bind it to
142 // the renderer that initiated it. The lower 32 bits of
143 // transaction_id are guaranteed to be unique within that renderer.
144 base::ProcessId pid = peer_pid();
145 DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits";
146 COMPILE_ASSERT(sizeof(base::ProcessId) <= sizeof(int32),
147 Process_ID_must_fit_in_32_bits);
149 return transaction_id | (static_cast<uint64>(pid) << 32);
152 int64 IndexedDBDispatcherHost::RendererTransactionId(
153 int64 host_transaction_id) {
154 DCHECK(host_transaction_id >> 32 == peer_pid())
155 << "Invalid renderer target for transaction id";
156 return host_transaction_id & 0xffffffff;
160 uint32 IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
161 int64 host_transaction_id) {
162 return host_transaction_id & 0xffffffff;
166 uint32 IndexedDBDispatcherHost::TransactionIdToProcessId(
167 int64 host_transaction_id) {
168 return (host_transaction_id >> 32) & 0xffffffff;
172 IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
173 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
174 return cursor_dispatcher_host_->map_.Lookup(ipc_cursor_id);
177 ::IndexedDBDatabaseMetadata IndexedDBDispatcherHost::ConvertMetadata(
178 const content::IndexedDBDatabaseMetadata& web_metadata) {
179 ::IndexedDBDatabaseMetadata metadata;
180 metadata.id = web_metadata.id;
181 metadata.name = web_metadata.name;
182 metadata.version = web_metadata.version;
183 metadata.int_version = web_metadata.int_version;
184 metadata.max_object_store_id = web_metadata.max_object_store_id;
186 for (content::IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator iter =
187 web_metadata.object_stores.begin();
188 iter != web_metadata.object_stores.end();
191 const content::IndexedDBObjectStoreMetadata& web_store_metadata =
193 ::IndexedDBObjectStoreMetadata idb_store_metadata;
194 idb_store_metadata.id = web_store_metadata.id;
195 idb_store_metadata.name = web_store_metadata.name;
196 idb_store_metadata.keyPath = web_store_metadata.key_path;
197 idb_store_metadata.autoIncrement = web_store_metadata.auto_increment;
198 idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
200 for (content::IndexedDBObjectStoreMetadata::IndexMap::const_iterator
201 index_iter = web_store_metadata.indexes.begin();
202 index_iter != web_store_metadata.indexes.end();
204 const content::IndexedDBIndexMetadata& web_index_metadata =
206 ::IndexedDBIndexMetadata idb_index_metadata;
207 idb_index_metadata.id = web_index_metadata.id;
208 idb_index_metadata.name = web_index_metadata.name;
209 idb_index_metadata.keyPath = web_index_metadata.key_path;
210 idb_index_metadata.unique = web_index_metadata.unique;
211 idb_index_metadata.multiEntry = web_index_metadata.multi_entry;
212 idb_store_metadata.indexes.push_back(idb_index_metadata);
214 metadata.object_stores.push_back(idb_store_metadata);
219 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
220 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) {
221 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
222 base::FilePath indexed_db_path = indexed_db_context_->data_path();
225 webkit_database::GetOriginFromIdentifier(params.database_identifier);
227 Context()->GetIDBFactory()->GetDatabaseNames(
228 new IndexedDBCallbacks(
229 this, params.ipc_thread_id, params.ipc_callbacks_id),
234 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
235 const IndexedDBHostMsg_FactoryOpen_Params& params) {
236 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
237 base::FilePath indexed_db_path = indexed_db_context_->data_path();
240 webkit_database::GetOriginFromIdentifier(params.database_identifier);
242 int64 host_transaction_id = HostTransactionId(params.transaction_id);
244 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
245 // created) if this origin is already over quota.
246 scoped_refptr<IndexedDBCallbacks> callbacks =
247 new IndexedDBCallbacks(this,
248 params.ipc_thread_id,
249 params.ipc_callbacks_id,
250 params.ipc_database_callbacks_id,
253 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
254 new IndexedDBDatabaseCallbacks(
255 this, params.ipc_thread_id, params.ipc_database_callbacks_id);
256 Context()->GetIDBFactory()->Open(params.name,
265 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
266 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
267 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
269 webkit_database::GetOriginFromIdentifier(params.database_identifier);
270 base::FilePath indexed_db_path = indexed_db_context_->data_path();
271 Context()->GetIDBFactory()->DeleteDatabase(
273 new IndexedDBCallbacks(
274 this, params.ipc_thread_id, params.ipc_callbacks_id),
279 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
281 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
282 if (!database_dispatcher_host_)
284 TransactionIDToURLMap& transaction_url_map =
285 database_dispatcher_host_->transaction_url_map_;
286 TransactionIDToSizeMap& transaction_size_map =
287 database_dispatcher_host_->transaction_size_map_;
288 TransactionIDToDatabaseIDMap& transaction_database_map =
289 database_dispatcher_host_->transaction_database_map_;
291 Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
292 transaction_url_map.erase(host_transaction_id);
293 transaction_size_map.erase(host_transaction_id);
294 transaction_database_map.erase(host_transaction_id);
297 //////////////////////////////////////////////////////////////////////
301 template <typename ObjectType>
302 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
303 IDMap<ObjectType, IDMapOwnPointer>* map,
304 int32 ipc_return_object_id) {
305 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
306 ObjectType* return_object = map->Lookup(ipc_return_object_id);
307 if (!return_object) {
308 NOTREACHED() << "Uh oh, couldn't find object with id "
309 << ipc_return_object_id;
310 RecordAction(UserMetricsAction("BadMessageTerminate_IDBMF"));
311 BadMessageReceived();
313 return return_object;
316 template <typename ObjectType>
317 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
318 RefIDMap<ObjectType>* map,
319 int32 ipc_return_object_id) {
320 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
321 ObjectType* return_object = map->Lookup(ipc_return_object_id);
322 if (!return_object) {
323 NOTREACHED() << "Uh oh, couldn't find object with id "
324 << ipc_return_object_id;
325 RecordAction(UserMetricsAction("BadMessageTerminate_IDBMF"));
326 BadMessageReceived();
328 return return_object;
331 template <typename MapType>
332 void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) {
333 GetOrTerminateProcess(map, ipc_object_id);
334 map->Remove(ipc_object_id);
337 //////////////////////////////////////////////////////////////////////
338 // IndexedDBDispatcherHost::DatabaseDispatcherHost
341 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
342 IndexedDBDispatcherHost* parent)
344 map_.set_check_on_null_data(true);
347 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
348 // TODO(alecflett): uncomment these when we find the source of these leaks.
349 // DCHECK(transaction_size_map_.empty());
350 // DCHECK(transaction_url_map_.empty());
353 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
355 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
356 // Abort outstanding transactions started by connections in the associated
357 // front-end to unblock later transactions. This should only occur on unclean
358 // (crash) or abrupt (process-kill) shutdowns.
359 for (TransactionIDToDatabaseIDMap::iterator iter =
360 transaction_database_map_.begin();
361 iter != transaction_database_map_.end();) {
362 int64 transaction_id = iter->first;
363 int32 ipc_database_id = iter->second;
365 IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
366 if (connection && connection->IsConnected()) {
367 connection->database()->Abort(
369 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError));
372 DCHECK(transaction_database_map_.empty());
374 for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin();
375 iter != database_url_map_.end();
377 IndexedDBConnection* connection = map_.Lookup(iter->first);
378 if (connection && connection->IsConnected()) {
380 parent_->Context()->ConnectionClosed(iter->second, connection);
385 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
386 const IPC::Message& message,
389 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
391 IPC_BEGIN_MESSAGE_MAP_EX(
392 IndexedDBDispatcherHost::DatabaseDispatcherHost, message, *msg_is_ok)
393 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
395 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
397 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
399 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
400 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
401 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
402 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPut)
403 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
404 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
406 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor)
407 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount)
408 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange)
409 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear)
410 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex)
411 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex)
412 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort)
413 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit)
414 IPC_MESSAGE_UNHANDLED(handled = false)
415 IPC_END_MESSAGE_MAP()
419 void IndexedDBDispatcherHost::DatabaseDispatcherHost::Send(
420 IPC::Message* message) {
421 parent_->Send(message);
424 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
425 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
427 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
428 IndexedDBConnection* connection =
429 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
430 if (!connection || !connection->IsConnected())
433 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
434 connection->database()->CreateObjectStore(host_transaction_id,
435 params.object_store_id,
438 params.auto_increment);
439 if (parent_->Context()->IsOverQuota(
440 database_url_map_[params.ipc_database_id])) {
441 connection->database()->Abort(
443 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionQuotaError));
447 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
448 int32 ipc_database_id,
449 int64 transaction_id,
450 int64 object_store_id) {
452 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
453 IndexedDBConnection* connection =
454 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
455 if (!connection || !connection->IsConnected())
458 connection->database()->DeleteObjectStore(
459 parent_->HostTransactionId(transaction_id), object_store_id);
462 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
463 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
465 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
466 IndexedDBConnection* connection =
467 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
468 if (!connection || !connection->IsConnected())
471 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
473 if (transaction_database_map_.find(host_transaction_id) !=
474 transaction_database_map_.end()) {
475 DLOG(ERROR) << "Duplicate host_transaction_id.";
479 connection->database()->CreateTransaction(
480 host_transaction_id, connection, params.object_store_ids, params.mode);
481 transaction_database_map_[host_transaction_id] = params.ipc_database_id;
482 parent_->RegisterTransactionId(host_transaction_id,
483 database_url_map_[params.ipc_database_id]);
486 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
487 int32 ipc_database_id) {
489 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
490 IndexedDBConnection* connection =
491 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
492 if (!connection || !connection->IsConnected())
497 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
498 int32 ipc_object_id) {
500 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
501 IndexedDBConnection* connection = map_.Lookup(ipc_object_id);
503 ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
504 database_url_map_.erase(ipc_object_id);
505 parent_->DestroyObject(&map_, ipc_object_id);
508 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
509 const IndexedDBHostMsg_DatabaseGet_Params& params) {
511 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
512 IndexedDBConnection* connection =
513 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
514 if (!connection || !connection->IsConnected())
517 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
518 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
519 connection->database()->Get(
520 parent_->HostTransactionId(params.transaction_id),
521 params.object_store_id,
523 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
528 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
529 const IndexedDBHostMsg_DatabasePut_Params& params) {
531 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
533 IndexedDBConnection* connection =
534 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
535 if (!connection || !connection->IsConnected())
537 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
538 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
540 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
541 // TODO(alecflett): Avoid a copy here.
542 std::string value_copy(params.value);
543 connection->database()->Put(
545 params.object_store_id,
547 make_scoped_ptr(new IndexedDBKey(params.key)),
548 static_cast<IndexedDBDatabase::PutMode>(params.put_mode),
552 TransactionIDToSizeMap* map =
553 &parent_->database_dispatcher_host_->transaction_size_map_;
554 // Size can't be big enough to overflow because it represents the
555 // actual bytes passed through IPC.
556 (*map)[host_transaction_id] += params.value.size();
559 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
560 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
562 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
563 IndexedDBConnection* connection =
564 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
565 if (!connection || !connection->IsConnected())
568 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
569 if (params.index_ids.size() != params.index_keys.size()) {
570 connection->database()->Abort(
572 IndexedDBDatabaseError(
573 WebKit::WebIDBDatabaseExceptionUnknownError,
574 "Malformed IPC message: index_ids.size() != index_keys.size()"));
578 connection->database()->SetIndexKeys(
580 params.object_store_id,
581 make_scoped_ptr(new IndexedDBKey(params.primary_key)),
586 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
587 int32 ipc_database_id,
588 int64 transaction_id,
589 int64 object_store_id,
590 const std::vector<int64>& index_ids) {
592 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
593 IndexedDBConnection* connection =
594 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
595 if (!connection || !connection->IsConnected())
598 connection->database()->SetIndexesReady(
599 parent_->HostTransactionId(transaction_id), object_store_id, index_ids);
602 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
603 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
605 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
606 IndexedDBConnection* connection =
607 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
608 if (!connection || !connection->IsConnected())
611 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
612 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1));
613 connection->database()->OpenCursor(
614 parent_->HostTransactionId(params.transaction_id),
615 params.object_store_id,
617 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
618 static_cast<indexed_db::CursorDirection>(params.direction),
620 static_cast<IndexedDBDatabase::TaskType>(params.task_type),
624 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
625 const IndexedDBHostMsg_DatabaseCount_Params& params) {
627 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
628 IndexedDBConnection* connection =
629 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
630 if (!connection || !connection->IsConnected())
633 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
634 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
635 connection->database()->Count(
636 parent_->HostTransactionId(params.transaction_id),
637 params.object_store_id,
639 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
643 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
644 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
646 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
647 IndexedDBConnection* connection =
648 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
649 if (!connection || !connection->IsConnected())
652 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
653 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
654 connection->database()->DeleteRange(
655 parent_->HostTransactionId(params.transaction_id),
656 params.object_store_id,
657 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
661 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
663 int32 ipc_callbacks_id,
664 int32 ipc_database_id,
665 int64 transaction_id,
666 int64 object_store_id) {
668 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
669 IndexedDBConnection* connection =
670 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
671 if (!connection || !connection->IsConnected())
674 scoped_refptr<IndexedDBCallbacks> callbacks(
675 new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id));
677 connection->database()->Clear(
678 parent_->HostTransactionId(transaction_id), object_store_id, callbacks);
681 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
682 int32 ipc_database_id,
683 int64 transaction_id) {
685 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
686 IndexedDBConnection* connection =
687 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
688 if (!connection || !connection->IsConnected())
691 connection->database()->Abort(parent_->HostTransactionId(transaction_id));
694 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
695 int32 ipc_database_id,
696 int64 transaction_id) {
698 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
699 IndexedDBConnection* connection =
700 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
701 if (!connection || !connection->IsConnected())
704 int64 host_transaction_id = parent_->HostTransactionId(transaction_id);
705 int64 transaction_size = transaction_size_map_[host_transaction_id];
706 if (transaction_size &&
707 parent_->Context()->WouldBeOverQuota(
708 transaction_url_map_[host_transaction_id], transaction_size)) {
709 connection->database()->Abort(
711 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionQuotaError));
715 connection->database()->Commit(host_transaction_id);
718 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
719 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
721 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
722 IndexedDBConnection* connection =
723 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
724 if (!connection || !connection->IsConnected())
727 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
728 connection->database()->CreateIndex(host_transaction_id,
729 params.object_store_id,
735 if (parent_->Context()->IsOverQuota(
736 database_url_map_[params.ipc_database_id])) {
737 connection->database()->Abort(
739 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionQuotaError));
743 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
744 int32 ipc_database_id,
745 int64 transaction_id,
746 int64 object_store_id,
749 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
750 IndexedDBConnection* connection =
751 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
752 if (!connection || !connection->IsConnected())
755 connection->database()->DeleteIndex(
756 parent_->HostTransactionId(transaction_id), object_store_id, index_id);
759 //////////////////////////////////////////////////////////////////////
760 // IndexedDBDispatcherHost::CursorDispatcherHost
763 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
764 IndexedDBDispatcherHost* parent)
766 map_.set_check_on_null_data(true);
769 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
771 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
772 const IPC::Message& message,
775 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
778 IPC_BEGIN_MESSAGE_MAP_EX(
779 IndexedDBDispatcherHost::CursorDispatcherHost, message, *msg_is_ok)
780 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance)
781 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
782 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch)
783 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset)
784 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
785 IPC_MESSAGE_UNHANDLED(handled = false)
786 IPC_END_MESSAGE_MAP()
790 void IndexedDBDispatcherHost::CursorDispatcherHost::Send(
791 IPC::Message* message) {
792 parent_->Send(message);
795 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
798 int32 ipc_callbacks_id,
799 unsigned long count) {
801 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
802 IndexedDBCursor* idb_cursor =
803 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
809 new IndexedDBCallbacks(
810 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
813 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
816 int32 ipc_callbacks_id,
817 const IndexedDBKey& key) {
819 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
820 IndexedDBCursor* idb_cursor =
821 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
825 idb_cursor->Continue(
826 make_scoped_ptr(new IndexedDBKey(key)),
827 new IndexedDBCallbacks(
828 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
831 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
834 int32 ipc_callbacks_id,
837 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
838 IndexedDBCursor* idb_cursor =
839 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
843 idb_cursor->PrefetchContinue(
845 new IndexedDBCallbacks(
846 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
849 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
852 int unused_prefetches) {
854 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
855 IndexedDBCursor* idb_cursor =
856 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
860 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
863 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
864 int32 ipc_object_id) {
866 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
867 parent_->DestroyObject(&map_, ipc_object_id);
870 } // namespace content