Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_dispatcher_host.cc
blob4f49b0e190ae31ab029cdb1484dda1ca007e7363
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"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/process/process.h"
12 #include "base/stl_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "content/browser/child_process_security_policy_impl.h"
15 #include "content/browser/indexed_db/indexed_db_callbacks.h"
16 #include "content/browser/indexed_db/indexed_db_connection.h"
17 #include "content/browser/indexed_db/indexed_db_context_impl.h"
18 #include "content/browser/indexed_db/indexed_db_cursor.h"
19 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
20 #include "content/browser/indexed_db/indexed_db_metadata.h"
21 #include "content/browser/indexed_db/indexed_db_pending_connection.h"
22 #include "content/browser/indexed_db/indexed_db_value.h"
23 #include "content/browser/renderer_host/render_message_filter.h"
24 #include "content/common/indexed_db/indexed_db_messages.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/user_metrics.h"
27 #include "content/public/common/content_switches.h"
28 #include "content/public/common/result_codes.h"
29 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
30 #include "url/gurl.h"
31 #include "webkit/browser/blob/blob_storage_context.h"
32 #include "webkit/browser/database/database_util.h"
33 #include "webkit/common/database/database_identifier.h"
35 using webkit_database::DatabaseUtil;
36 using blink::WebIDBKey;
38 namespace content {
40 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
41 int ipc_process_id,
42 net::URLRequestContextGetter* request_context_getter,
43 IndexedDBContextImpl* indexed_db_context,
44 ChromeBlobStorageContext* blob_storage_context)
45 : BrowserMessageFilter(IndexedDBMsgStart),
46 request_context_getter_(request_context_getter),
47 request_context_(NULL),
48 indexed_db_context_(indexed_db_context),
49 blob_storage_context_(blob_storage_context),
50 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
51 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
52 ipc_process_id_(ipc_process_id) {
53 DCHECK(indexed_db_context_);
56 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
57 int ipc_process_id,
58 net::URLRequestContext* request_context,
59 IndexedDBContextImpl* indexed_db_context,
60 ChromeBlobStorageContext* blob_storage_context)
61 : BrowserMessageFilter(IndexedDBMsgStart),
62 request_context_(request_context),
63 indexed_db_context_(indexed_db_context),
64 blob_storage_context_(blob_storage_context),
65 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
66 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
67 ipc_process_id_(ipc_process_id) {
68 DCHECK(indexed_db_context_);
71 IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
72 STLDeleteValues(&blob_data_handle_map_);
75 void IndexedDBDispatcherHost::OnChannelConnected(int32 peer_pid) {
76 BrowserMessageFilter::OnChannelConnected(peer_pid);
78 if (request_context_getter_.get()) {
79 DCHECK(!request_context_);
80 request_context_ = request_context_getter_->GetURLRequestContext();
81 request_context_getter_ = NULL;
82 DCHECK(request_context_);
86 void IndexedDBDispatcherHost::OnChannelClosing() {
87 bool success = indexed_db_context_->TaskRunner()->PostTask(
88 FROM_HERE,
89 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this));
91 if (!success)
92 ResetDispatcherHosts();
95 void IndexedDBDispatcherHost::OnDestruct() const {
96 // The last reference to the dispatcher may be a posted task, which would
97 // be destructed on the IndexedDB thread. Without this override, that would
98 // take the dispatcher with it. Since the dispatcher may be keeping the
99 // IndexedDBContext alive, it might be destructed to on its own thread,
100 // which is not supported. Ensure destruction runs on the IO thread instead.
101 BrowserThread::DeleteOnIOThread::Destruct(this);
104 void IndexedDBDispatcherHost::ResetDispatcherHosts() {
105 // It is important that the various *_dispatcher_host_ members are reset
106 // on the IndexedDB thread, since there might be incoming messages on that
107 // thread, and we must not reset the dispatcher hosts until after those
108 // messages are processed.
109 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
111 // Note that we explicitly separate CloseAll() from destruction of the
112 // DatabaseDispatcherHost, since CloseAll() can invoke callbacks which need to
113 // be dispatched through database_dispatcher_host_.
114 database_dispatcher_host_->CloseAll();
115 database_dispatcher_host_.reset();
116 cursor_dispatcher_host_.reset();
119 base::TaskRunner* IndexedDBDispatcherHost::OverrideTaskRunnerForMessage(
120 const IPC::Message& message) {
121 if (IPC_MESSAGE_CLASS(message) == IndexedDBMsgStart &&
122 message.type() != IndexedDBHostMsg_DatabasePut::ID)
123 return indexed_db_context_->TaskRunner();
124 return NULL;
127 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message,
128 bool* message_was_ok) {
129 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
130 return false;
132 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread() ||
133 message.type() == IndexedDBHostMsg_DatabasePut::ID);
135 bool handled =
136 database_dispatcher_host_->OnMessageReceived(message, message_was_ok) ||
137 cursor_dispatcher_host_->OnMessageReceived(message, message_was_ok);
139 if (!handled) {
140 handled = true;
141 IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost, message, *message_was_ok)
142 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames,
143 OnIDBFactoryGetDatabaseNames)
144 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen)
145 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase,
146 OnIDBFactoryDeleteDatabase)
147 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_AckReceivedBlobs, OnAckReceivedBlobs)
148 IPC_MESSAGE_UNHANDLED(handled = false)
149 IPC_END_MESSAGE_MAP()
151 return handled;
154 int32 IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) {
155 if (!cursor_dispatcher_host_) {
156 return 0;
158 return cursor_dispatcher_host_->map_.Add(cursor);
161 int32 IndexedDBDispatcherHost::Add(IndexedDBConnection* connection,
162 int32 ipc_thread_id,
163 const GURL& origin_url) {
164 if (!database_dispatcher_host_) {
165 connection->Close();
166 delete connection;
167 return -1;
169 int32 ipc_database_id = database_dispatcher_host_->map_.Add(connection);
170 Context()->ConnectionOpened(origin_url, connection);
171 database_dispatcher_host_->database_url_map_[ipc_database_id] = origin_url;
172 return ipc_database_id;
175 void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id,
176 const GURL& url) {
177 if (!database_dispatcher_host_)
178 return;
179 database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url;
182 int64 IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id) {
183 // Inject the renderer process id into the transaction id, to
184 // uniquely identify this transaction, and effectively bind it to
185 // the renderer that initiated it. The lower 32 bits of
186 // transaction_id are guaranteed to be unique within that renderer.
187 base::ProcessId pid = peer_pid();
188 DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits";
189 COMPILE_ASSERT(sizeof(base::ProcessId) <= sizeof(int32),
190 Process_ID_must_fit_in_32_bits);
192 return transaction_id | (static_cast<uint64>(pid) << 32);
195 int64 IndexedDBDispatcherHost::RendererTransactionId(
196 int64 host_transaction_id) {
197 DCHECK(host_transaction_id >> 32 == peer_pid())
198 << "Invalid renderer target for transaction id";
199 return host_transaction_id & 0xffffffff;
202 // static
203 uint32 IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
204 int64 host_transaction_id) {
205 return host_transaction_id & 0xffffffff;
208 // static
209 uint32 IndexedDBDispatcherHost::TransactionIdToProcessId(
210 int64 host_transaction_id) {
211 return (host_transaction_id >> 32) & 0xffffffff;
214 void IndexedDBDispatcherHost::HoldBlobDataHandle(
215 const std::string& uuid,
216 scoped_ptr<webkit_blob::BlobDataHandle>& blob_data_handle) {
217 DCHECK(!ContainsKey(blob_data_handle_map_, uuid));
218 blob_data_handle_map_[uuid] = blob_data_handle.release();
221 void IndexedDBDispatcherHost::DropBlobDataHandle(const std::string& uuid) {
222 BlobDataHandleMap::iterator iter = blob_data_handle_map_.find(uuid);
223 if (iter != blob_data_handle_map_.end()) {
224 delete iter->second;
225 blob_data_handle_map_.erase(iter);
226 } else {
227 DLOG(FATAL) << "Failed to find blob UUID in map:" << uuid;
231 IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
232 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
233 return cursor_dispatcher_host_->map_.Lookup(ipc_cursor_id);
236 ::IndexedDBDatabaseMetadata IndexedDBDispatcherHost::ConvertMetadata(
237 const content::IndexedDBDatabaseMetadata& web_metadata) {
238 ::IndexedDBDatabaseMetadata metadata;
239 metadata.id = web_metadata.id;
240 metadata.name = web_metadata.name;
241 metadata.version = web_metadata.version;
242 metadata.int_version = web_metadata.int_version;
243 metadata.max_object_store_id = web_metadata.max_object_store_id;
245 for (content::IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator iter =
246 web_metadata.object_stores.begin();
247 iter != web_metadata.object_stores.end();
248 ++iter) {
250 const content::IndexedDBObjectStoreMetadata& web_store_metadata =
251 iter->second;
252 ::IndexedDBObjectStoreMetadata idb_store_metadata;
253 idb_store_metadata.id = web_store_metadata.id;
254 idb_store_metadata.name = web_store_metadata.name;
255 idb_store_metadata.keyPath = web_store_metadata.key_path;
256 idb_store_metadata.autoIncrement = web_store_metadata.auto_increment;
257 idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
259 for (content::IndexedDBObjectStoreMetadata::IndexMap::const_iterator
260 index_iter = web_store_metadata.indexes.begin();
261 index_iter != web_store_metadata.indexes.end();
262 ++index_iter) {
263 const content::IndexedDBIndexMetadata& web_index_metadata =
264 index_iter->second;
265 ::IndexedDBIndexMetadata idb_index_metadata;
266 idb_index_metadata.id = web_index_metadata.id;
267 idb_index_metadata.name = web_index_metadata.name;
268 idb_index_metadata.keyPath = web_index_metadata.key_path;
269 idb_index_metadata.unique = web_index_metadata.unique;
270 idb_index_metadata.multiEntry = web_index_metadata.multi_entry;
271 idb_store_metadata.indexes.push_back(idb_index_metadata);
273 metadata.object_stores.push_back(idb_store_metadata);
275 return metadata;
278 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
279 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) {
280 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
281 base::FilePath indexed_db_path = indexed_db_context_->data_path();
283 GURL origin_url =
284 webkit_database::GetOriginFromIdentifier(params.database_identifier);
286 Context()->GetIDBFactory()->GetDatabaseNames(
287 new IndexedDBCallbacks(
288 this, params.ipc_thread_id, params.ipc_callbacks_id),
289 origin_url,
290 indexed_db_path,
291 request_context_);
294 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
295 const IndexedDBHostMsg_FactoryOpen_Params& params) {
296 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
297 base::FilePath indexed_db_path = indexed_db_context_->data_path();
299 GURL origin_url =
300 webkit_database::GetOriginFromIdentifier(params.database_identifier);
302 int64 host_transaction_id = HostTransactionId(params.transaction_id);
304 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
305 // created) if this origin is already over quota.
306 scoped_refptr<IndexedDBCallbacks> callbacks =
307 new IndexedDBCallbacks(this,
308 params.ipc_thread_id,
309 params.ipc_callbacks_id,
310 params.ipc_database_callbacks_id,
311 host_transaction_id,
312 origin_url);
313 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
314 new IndexedDBDatabaseCallbacks(
315 this, params.ipc_thread_id, params.ipc_database_callbacks_id);
316 IndexedDBPendingConnection connection(callbacks,
317 database_callbacks,
318 ipc_process_id_,
319 host_transaction_id,
320 params.version);
321 DCHECK(request_context_);
322 Context()->GetIDBFactory()->Open(
323 params.name, connection, request_context_, origin_url, indexed_db_path);
326 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
327 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
328 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
329 GURL origin_url =
330 webkit_database::GetOriginFromIdentifier(params.database_identifier);
331 base::FilePath indexed_db_path = indexed_db_context_->data_path();
332 DCHECK(request_context_);
333 Context()->GetIDBFactory()->DeleteDatabase(
334 params.name,
335 request_context_,
336 new IndexedDBCallbacks(
337 this, params.ipc_thread_id, params.ipc_callbacks_id),
338 origin_url,
339 indexed_db_path);
342 // OnPutHelper exists only to allow us to hop threads while holding a reference
343 // to the IndexedDBDispatcherHost.
344 void IndexedDBDispatcherHost::OnPutHelper(
345 const IndexedDBHostMsg_DatabasePut_Params& params,
346 std::vector<webkit_blob::BlobDataHandle*> handles) {
347 database_dispatcher_host_->OnPut(params, handles);
350 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
351 const std::vector<std::string>& uuids) {
352 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
353 std::vector<std::string>::const_iterator iter;
354 for (iter = uuids.begin(); iter != uuids.end(); ++iter)
355 DropBlobDataHandle(*iter);
358 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
359 bool committed) {
360 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
361 if (!database_dispatcher_host_)
362 return;
363 TransactionIDToURLMap& transaction_url_map =
364 database_dispatcher_host_->transaction_url_map_;
365 TransactionIDToSizeMap& transaction_size_map =
366 database_dispatcher_host_->transaction_size_map_;
367 TransactionIDToDatabaseIDMap& transaction_database_map =
368 database_dispatcher_host_->transaction_database_map_;
369 if (committed)
370 Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
371 transaction_url_map.erase(host_transaction_id);
372 transaction_size_map.erase(host_transaction_id);
373 transaction_database_map.erase(host_transaction_id);
376 //////////////////////////////////////////////////////////////////////
377 // Helper templates.
380 template <typename ObjectType>
381 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
382 IDMap<ObjectType, IDMapOwnPointer>* map,
383 int32 ipc_return_object_id) {
384 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
385 ObjectType* return_object = map->Lookup(ipc_return_object_id);
386 if (!return_object) {
387 NOTREACHED() << "Uh oh, couldn't find object with id "
388 << ipc_return_object_id;
389 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
390 BadMessageReceived();
392 return return_object;
395 template <typename ObjectType>
396 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
397 RefIDMap<ObjectType>* map,
398 int32 ipc_return_object_id) {
399 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
400 ObjectType* return_object = map->Lookup(ipc_return_object_id);
401 if (!return_object) {
402 NOTREACHED() << "Uh oh, couldn't find object with id "
403 << ipc_return_object_id;
404 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
405 BadMessageReceived();
407 return return_object;
410 template <typename MapType>
411 void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) {
412 GetOrTerminateProcess(map, ipc_object_id);
413 map->Remove(ipc_object_id);
416 //////////////////////////////////////////////////////////////////////
417 // IndexedDBDispatcherHost::DatabaseDispatcherHost
420 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
421 IndexedDBDispatcherHost* parent)
422 : parent_(parent) {
423 map_.set_check_on_null_data(true);
426 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
427 // TODO(alecflett): uncomment these when we find the source of these leaks.
428 // DCHECK(transaction_size_map_.empty());
429 // DCHECK(transaction_url_map_.empty());
432 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
433 DCHECK(
434 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
435 // Abort outstanding transactions started by connections in the associated
436 // front-end to unblock later transactions. This should only occur on unclean
437 // (crash) or abrupt (process-kill) shutdowns.
438 for (TransactionIDToDatabaseIDMap::iterator iter =
439 transaction_database_map_.begin();
440 iter != transaction_database_map_.end();) {
441 int64 transaction_id = iter->first;
442 int32 ipc_database_id = iter->second;
443 ++iter;
444 IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
445 if (connection && connection->IsConnected()) {
446 connection->database()->Abort(
447 transaction_id,
448 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError));
451 DCHECK(transaction_database_map_.empty());
453 for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin();
454 iter != database_url_map_.end();
455 iter++) {
456 IndexedDBConnection* connection = map_.Lookup(iter->first);
457 if (connection && connection->IsConnected()) {
458 connection->Close();
459 parent_->Context()->ConnectionClosed(iter->second, connection);
464 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
465 const IPC::Message& message,
466 bool* msg_is_ok) {
468 DCHECK(
469 (message.type() == IndexedDBHostMsg_DatabasePut::ID) ||
470 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
472 bool handled = true;
473 IPC_BEGIN_MESSAGE_MAP_EX(
474 IndexedDBDispatcherHost::DatabaseDispatcherHost, message, *msg_is_ok)
475 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
476 OnCreateObjectStore)
477 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
478 OnDeleteObjectStore)
479 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
480 OnCreateTransaction)
481 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
482 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
483 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
484 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
485 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
486 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
487 OnSetIndexesReady)
488 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor)
489 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount)
490 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange)
491 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear)
492 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex)
493 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex)
494 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort)
495 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit)
496 IPC_MESSAGE_UNHANDLED(handled = false)
497 IPC_END_MESSAGE_MAP()
499 return handled;
502 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
503 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
504 DCHECK(
505 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
506 IndexedDBConnection* connection =
507 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
508 if (!connection || !connection->IsConnected())
509 return;
511 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
512 connection->database()->CreateObjectStore(host_transaction_id,
513 params.object_store_id,
514 params.name,
515 params.key_path,
516 params.auto_increment);
517 if (parent_->Context()->IsOverQuota(
518 database_url_map_[params.ipc_database_id])) {
519 connection->database()->Abort(
520 host_transaction_id,
521 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
525 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
526 int32 ipc_database_id,
527 int64 transaction_id,
528 int64 object_store_id) {
529 DCHECK(
530 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
531 IndexedDBConnection* connection =
532 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
533 if (!connection || !connection->IsConnected())
534 return;
536 connection->database()->DeleteObjectStore(
537 parent_->HostTransactionId(transaction_id), object_store_id);
540 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
541 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
542 DCHECK(
543 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
544 IndexedDBConnection* connection =
545 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
546 if (!connection || !connection->IsConnected())
547 return;
549 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
551 if (transaction_database_map_.find(host_transaction_id) !=
552 transaction_database_map_.end()) {
553 DLOG(ERROR) << "Duplicate host_transaction_id.";
554 return;
557 connection->database()->CreateTransaction(
558 host_transaction_id, connection, params.object_store_ids, params.mode);
559 transaction_database_map_[host_transaction_id] = params.ipc_database_id;
560 parent_->RegisterTransactionId(host_transaction_id,
561 database_url_map_[params.ipc_database_id]);
564 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
565 int32 ipc_database_id) {
566 DCHECK(
567 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
568 IndexedDBConnection* connection =
569 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
570 if (!connection || !connection->IsConnected())
571 return;
572 connection->Close();
575 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
576 int32 ipc_object_id) {
577 DCHECK(
578 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
579 IndexedDBConnection* connection = map_.Lookup(ipc_object_id);
580 if (connection->IsConnected())
581 connection->Close();
582 parent_->Context()
583 ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
584 database_url_map_.erase(ipc_object_id);
585 parent_->DestroyObject(&map_, ipc_object_id);
588 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
589 const IndexedDBHostMsg_DatabaseGet_Params& params) {
590 DCHECK(
591 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
592 IndexedDBConnection* connection =
593 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
594 if (!connection || !connection->IsConnected())
595 return;
597 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
598 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
599 connection->database()->Get(
600 parent_->HostTransactionId(params.transaction_id),
601 params.object_store_id,
602 params.index_id,
603 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
604 params.key_only,
605 callbacks);
608 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
609 const IndexedDBHostMsg_DatabasePut_Params& params) {
610 std::vector<webkit_blob::BlobDataHandle*> handles;
611 for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
612 const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
613 handles.push_back(parent_->blob_storage_context_->context()
614 ->GetBlobDataFromUUID(info.uuid)
615 .release());
617 parent_->indexed_db_context_->TaskRunner()->PostTask(
618 FROM_HERE,
619 base::Bind(
620 &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
623 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
624 const IndexedDBHostMsg_DatabasePut_Params& params,
625 std::vector<webkit_blob::BlobDataHandle*> handles) {
627 DCHECK(
628 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
630 ScopedVector<webkit_blob::BlobDataHandle> scoped_handles;
631 scoped_handles.swap(handles);
633 IndexedDBConnection* connection =
634 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
635 if (!connection || !connection->IsConnected())
636 return;
637 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
638 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
640 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
642 std::vector<IndexedDBBlobInfo> blob_info(params.blob_or_file_info.size());
644 ChildProcessSecurityPolicyImpl* policy =
645 ChildProcessSecurityPolicyImpl::GetInstance();
647 for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
648 const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
649 if (info.is_file) {
650 base::FilePath path = base::FilePath::FromUTF16Unsafe(info.file_path);
651 if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
652 parent_->BadMessageReceived();
653 return;
655 blob_info[i] =
656 IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type);
657 } else {
658 blob_info[i] = IndexedDBBlobInfo(info.uuid, info.mime_type, info.size);
662 // TODO(alecflett): Avoid a copy here.
663 IndexedDBValue value;
664 value.bits = params.value;
665 value.blob_info.swap(blob_info);
666 connection->database()->Put(
667 host_transaction_id,
668 params.object_store_id,
669 &value,
670 &scoped_handles,
671 make_scoped_ptr(new IndexedDBKey(params.key)),
672 static_cast<IndexedDBDatabase::PutMode>(params.put_mode),
673 callbacks,
674 params.index_keys);
675 TransactionIDToSizeMap* map =
676 &parent_->database_dispatcher_host_->transaction_size_map_;
677 // Size can't be big enough to overflow because it represents the
678 // actual bytes passed through IPC.
679 (*map)[host_transaction_id] += params.value.size();
682 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
683 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
684 DCHECK(
685 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
686 IndexedDBConnection* connection =
687 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
688 if (!connection || !connection->IsConnected())
689 return;
691 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
692 connection->database()->SetIndexKeys(
693 host_transaction_id,
694 params.object_store_id,
695 make_scoped_ptr(new IndexedDBKey(params.primary_key)),
696 params.index_keys);
699 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
700 int32 ipc_database_id,
701 int64 transaction_id,
702 int64 object_store_id,
703 const std::vector<int64>& index_ids) {
704 DCHECK(
705 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
706 IndexedDBConnection* connection =
707 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
708 if (!connection || !connection->IsConnected())
709 return;
711 connection->database()->SetIndexesReady(
712 parent_->HostTransactionId(transaction_id), object_store_id, index_ids);
715 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
716 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
717 DCHECK(
718 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
719 IndexedDBConnection* connection =
720 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
721 if (!connection || !connection->IsConnected())
722 return;
724 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
725 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1));
726 connection->database()->OpenCursor(
727 parent_->HostTransactionId(params.transaction_id),
728 params.object_store_id,
729 params.index_id,
730 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
731 static_cast<indexed_db::CursorDirection>(params.direction),
732 params.key_only,
733 static_cast<IndexedDBDatabase::TaskType>(params.task_type),
734 callbacks);
737 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
738 const IndexedDBHostMsg_DatabaseCount_Params& params) {
739 DCHECK(
740 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
741 IndexedDBConnection* connection =
742 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
743 if (!connection || !connection->IsConnected())
744 return;
746 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
747 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
748 connection->database()->Count(
749 parent_->HostTransactionId(params.transaction_id),
750 params.object_store_id,
751 params.index_id,
752 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
753 callbacks);
756 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
757 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
758 DCHECK(
759 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
760 IndexedDBConnection* connection =
761 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
762 if (!connection || !connection->IsConnected())
763 return;
765 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
766 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
767 connection->database()->DeleteRange(
768 parent_->HostTransactionId(params.transaction_id),
769 params.object_store_id,
770 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
771 callbacks);
774 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
775 int32 ipc_thread_id,
776 int32 ipc_callbacks_id,
777 int32 ipc_database_id,
778 int64 transaction_id,
779 int64 object_store_id) {
780 DCHECK(
781 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
782 IndexedDBConnection* connection =
783 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
784 if (!connection || !connection->IsConnected())
785 return;
787 scoped_refptr<IndexedDBCallbacks> callbacks(
788 new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id));
790 connection->database()->Clear(
791 parent_->HostTransactionId(transaction_id), object_store_id, callbacks);
794 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
795 int32 ipc_database_id,
796 int64 transaction_id) {
797 DCHECK(
798 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
799 IndexedDBConnection* connection =
800 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
801 if (!connection || !connection->IsConnected())
802 return;
804 connection->database()->Abort(parent_->HostTransactionId(transaction_id));
807 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
808 int32 ipc_database_id,
809 int64 transaction_id) {
810 DCHECK(
811 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
812 IndexedDBConnection* connection =
813 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
814 if (!connection || !connection->IsConnected())
815 return;
817 int64 host_transaction_id = parent_->HostTransactionId(transaction_id);
818 int64 transaction_size = transaction_size_map_[host_transaction_id];
819 if (transaction_size &&
820 parent_->Context()->WouldBeOverQuota(
821 transaction_url_map_[host_transaction_id], transaction_size)) {
822 connection->database()->Abort(
823 host_transaction_id,
824 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
825 return;
828 connection->database()->Commit(host_transaction_id);
831 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
832 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
833 DCHECK(
834 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
835 IndexedDBConnection* connection =
836 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
837 if (!connection || !connection->IsConnected())
838 return;
840 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
841 connection->database()->CreateIndex(host_transaction_id,
842 params.object_store_id,
843 params.index_id,
844 params.name,
845 params.key_path,
846 params.unique,
847 params.multi_entry);
848 if (parent_->Context()->IsOverQuota(
849 database_url_map_[params.ipc_database_id])) {
850 connection->database()->Abort(
851 host_transaction_id,
852 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
856 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
857 int32 ipc_database_id,
858 int64 transaction_id,
859 int64 object_store_id,
860 int64 index_id) {
861 DCHECK(
862 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
863 IndexedDBConnection* connection =
864 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
865 if (!connection || !connection->IsConnected())
866 return;
868 connection->database()->DeleteIndex(
869 parent_->HostTransactionId(transaction_id), object_store_id, index_id);
872 //////////////////////////////////////////////////////////////////////
873 // IndexedDBDispatcherHost::CursorDispatcherHost
876 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
877 IndexedDBDispatcherHost* parent)
878 : parent_(parent) {
879 map_.set_check_on_null_data(true);
882 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
884 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
885 const IPC::Message& message,
886 bool* msg_is_ok) {
887 bool handled = true;
888 IPC_BEGIN_MESSAGE_MAP_EX(
889 IndexedDBDispatcherHost::CursorDispatcherHost, message, *msg_is_ok)
890 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance)
891 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
892 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch)
893 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset)
894 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
895 IPC_MESSAGE_UNHANDLED(handled = false)
896 IPC_END_MESSAGE_MAP()
898 DCHECK(
899 !handled ||
900 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
902 return handled;
905 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
906 int32 ipc_cursor_id,
907 int32 ipc_thread_id,
908 int32 ipc_callbacks_id,
909 unsigned long count) {
910 DCHECK(
911 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
912 IndexedDBCursor* idb_cursor =
913 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
914 if (!idb_cursor)
915 return;
917 idb_cursor->Advance(
918 count,
919 new IndexedDBCallbacks(
920 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
923 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
924 int32 ipc_cursor_id,
925 int32 ipc_thread_id,
926 int32 ipc_callbacks_id,
927 const IndexedDBKey& key,
928 const IndexedDBKey& primary_key) {
929 DCHECK(
930 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
931 IndexedDBCursor* idb_cursor =
932 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
933 if (!idb_cursor)
934 return;
936 idb_cursor->Continue(
937 key.IsValid() ? make_scoped_ptr(new IndexedDBKey(key))
938 : scoped_ptr<IndexedDBKey>(),
939 primary_key.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key))
940 : scoped_ptr<IndexedDBKey>(),
941 new IndexedDBCallbacks(
942 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
945 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
946 int32 ipc_cursor_id,
947 int32 ipc_thread_id,
948 int32 ipc_callbacks_id,
949 int n) {
950 DCHECK(
951 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
952 IndexedDBCursor* idb_cursor =
953 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
954 if (!idb_cursor)
955 return;
957 idb_cursor->PrefetchContinue(
959 new IndexedDBCallbacks(
960 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
963 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
964 int32 ipc_cursor_id,
965 int used_prefetches,
966 int unused_prefetches) {
967 DCHECK(
968 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
969 IndexedDBCursor* idb_cursor =
970 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
971 if (!idb_cursor)
972 return;
974 leveldb::Status s =
975 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
976 // TODO(cmumford): Handle this error (crbug.com/363397)
977 if (!s.ok())
978 DLOG(ERROR) << "Unable to reset prefetch";
981 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
982 int32 ipc_object_id) {
983 DCHECK(
984 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
985 parent_->DestroyObject(&map_, ipc_object_id);
988 } // namespace content