[IndexedDB] Adding traces, perf tests
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_dispatcher_host.cc
blob996e6a50ea73ac96d873744eb2d512cdca3a375b
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/guid.h"
11 #include "base/memory/scoped_vector.h"
12 #include "base/process/process.h"
13 #include "base/stl_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/browser/bad_message.h"
16 #include "content/browser/child_process_security_policy_impl.h"
17 #include "content/browser/indexed_db/indexed_db_callbacks.h"
18 #include "content/browser/indexed_db/indexed_db_connection.h"
19 #include "content/browser/indexed_db/indexed_db_context_impl.h"
20 #include "content/browser/indexed_db/indexed_db_cursor.h"
21 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
22 #include "content/browser/indexed_db/indexed_db_metadata.h"
23 #include "content/browser/indexed_db/indexed_db_pending_connection.h"
24 #include "content/browser/indexed_db/indexed_db_value.h"
25 #include "content/browser/renderer_host/render_message_filter.h"
26 #include "content/common/indexed_db/indexed_db_messages.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/user_metrics.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/result_codes.h"
31 #include "storage/browser/blob/blob_data_builder.h"
32 #include "storage/browser/blob/blob_storage_context.h"
33 #include "storage/browser/database/database_util.h"
34 #include "storage/common/database/database_identifier.h"
35 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
36 #include "url/gurl.h"
38 using storage::DatabaseUtil;
39 using blink::WebIDBKey;
41 namespace content {
43 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
44 int ipc_process_id,
45 net::URLRequestContextGetter* request_context_getter,
46 IndexedDBContextImpl* indexed_db_context,
47 ChromeBlobStorageContext* blob_storage_context)
48 : BrowserMessageFilter(IndexedDBMsgStart),
49 request_context_getter_(request_context_getter),
50 request_context_(NULL),
51 indexed_db_context_(indexed_db_context),
52 blob_storage_context_(blob_storage_context),
53 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
54 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
55 ipc_process_id_(ipc_process_id) {
56 DCHECK(indexed_db_context_.get());
59 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
60 int ipc_process_id,
61 net::URLRequestContext* request_context,
62 IndexedDBContextImpl* indexed_db_context,
63 ChromeBlobStorageContext* blob_storage_context)
64 : BrowserMessageFilter(IndexedDBMsgStart),
65 request_context_(request_context),
66 indexed_db_context_(indexed_db_context),
67 blob_storage_context_(blob_storage_context),
68 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
69 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
70 ipc_process_id_(ipc_process_id) {
71 DCHECK(indexed_db_context_.get());
74 IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
75 for (auto& iter : blob_data_handle_map_)
76 delete iter.second.first;
79 void IndexedDBDispatcherHost::OnChannelConnected(int32 peer_pid) {
80 BrowserMessageFilter::OnChannelConnected(peer_pid);
82 if (request_context_getter_.get()) {
83 DCHECK(!request_context_);
84 request_context_ = request_context_getter_->GetURLRequestContext();
85 request_context_getter_ = NULL;
86 DCHECK(request_context_);
90 void IndexedDBDispatcherHost::OnChannelClosing() {
91 bool success = indexed_db_context_->TaskRunner()->PostTask(
92 FROM_HERE,
93 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this));
95 if (!success)
96 ResetDispatcherHosts();
99 void IndexedDBDispatcherHost::OnDestruct() const {
100 // The last reference to the dispatcher may be a posted task, which would
101 // be destructed on the IndexedDB thread. Without this override, that would
102 // take the dispatcher with it. Since the dispatcher may be keeping the
103 // IndexedDBContext alive, it might be destructed to on its own thread,
104 // which is not supported. Ensure destruction runs on the IO thread instead.
105 BrowserThread::DeleteOnIOThread::Destruct(this);
108 void IndexedDBDispatcherHost::ResetDispatcherHosts() {
109 // It is important that the various *_dispatcher_host_ members are reset
110 // on the IndexedDB thread, since there might be incoming messages on that
111 // thread, and we must not reset the dispatcher hosts until after those
112 // messages are processed.
113 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
115 // Note that we explicitly separate CloseAll() from destruction of the
116 // DatabaseDispatcherHost, since CloseAll() can invoke callbacks which need to
117 // be dispatched through database_dispatcher_host_.
118 database_dispatcher_host_->CloseAll();
119 database_dispatcher_host_.reset();
120 cursor_dispatcher_host_.reset();
123 base::TaskRunner* IndexedDBDispatcherHost::OverrideTaskRunnerForMessage(
124 const IPC::Message& message) {
125 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
126 return NULL;
128 switch (message.type()) {
129 case IndexedDBHostMsg_DatabasePut::ID:
130 case IndexedDBHostMsg_AckReceivedBlobs::ID:
131 return NULL;
132 default:
133 return indexed_db_context_->TaskRunner();
137 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
138 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
139 return false;
141 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread() ||
142 (message.type() == IndexedDBHostMsg_DatabasePut::ID ||
143 message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID));
145 bool handled = database_dispatcher_host_->OnMessageReceived(message) ||
146 cursor_dispatcher_host_->OnMessageReceived(message);
148 if (!handled) {
149 handled = true;
150 IPC_BEGIN_MESSAGE_MAP(IndexedDBDispatcherHost, message)
151 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames,
152 OnIDBFactoryGetDatabaseNames)
153 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen)
154 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase,
155 OnIDBFactoryDeleteDatabase)
156 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_AckReceivedBlobs, OnAckReceivedBlobs)
157 IPC_MESSAGE_UNHANDLED(handled = false)
158 IPC_END_MESSAGE_MAP()
160 return handled;
163 int32 IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) {
164 if (!cursor_dispatcher_host_) {
165 return 0;
167 return cursor_dispatcher_host_->map_.Add(cursor);
170 int32 IndexedDBDispatcherHost::Add(IndexedDBConnection* connection,
171 int32 ipc_thread_id,
172 const GURL& origin_url) {
173 if (!database_dispatcher_host_) {
174 connection->Close();
175 delete connection;
176 return -1;
178 int32 ipc_database_id = database_dispatcher_host_->map_.Add(connection);
179 Context()->ConnectionOpened(origin_url, connection);
180 database_dispatcher_host_->database_url_map_[ipc_database_id] = origin_url;
181 return ipc_database_id;
184 void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id,
185 const GURL& url) {
186 if (!database_dispatcher_host_)
187 return;
188 database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url;
191 int64 IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id) {
192 // Inject the renderer process id into the transaction id, to
193 // uniquely identify this transaction, and effectively bind it to
194 // the renderer that initiated it. The lower 32 bits of
195 // transaction_id are guaranteed to be unique within that renderer.
196 base::ProcessId pid = peer_pid();
197 DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits";
198 static_assert(sizeof(base::ProcessId) <= sizeof(int32),
199 "Process ID must fit in 32 bits");
201 return transaction_id | (static_cast<uint64>(pid) << 32);
204 int64 IndexedDBDispatcherHost::RendererTransactionId(
205 int64 host_transaction_id) {
206 DCHECK(host_transaction_id >> 32 == peer_pid())
207 << "Invalid renderer target for transaction id";
208 return host_transaction_id & 0xffffffff;
211 // static
212 uint32 IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
213 int64 host_transaction_id) {
214 return host_transaction_id & 0xffffffff;
217 // static
218 uint32 IndexedDBDispatcherHost::TransactionIdToProcessId(
219 int64 host_transaction_id) {
220 return (host_transaction_id >> 32) & 0xffffffff;
223 std::string IndexedDBDispatcherHost::HoldBlobData(
224 const IndexedDBBlobInfo& blob_info) {
225 DCHECK_CURRENTLY_ON(BrowserThread::IO);
226 std::string uuid = blob_info.uuid();
227 storage::BlobStorageContext* context = blob_storage_context_->context();
228 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
229 if (uuid.empty()) {
230 uuid = base::GenerateGUID();
231 storage::BlobDataBuilder blob_data_builder(uuid);
232 blob_data_builder.set_content_type(base::UTF16ToUTF8(blob_info.type()));
233 blob_data_builder.AppendFile(blob_info.file_path(), 0, blob_info.size(),
234 blob_info.last_modified());
235 blob_data_handle = context->AddFinishedBlob(&blob_data_builder);
236 } else {
237 auto iter = blob_data_handle_map_.find(uuid);
238 if (iter != blob_data_handle_map_.end()) {
239 iter->second.second += 1;
240 return uuid;
242 blob_data_handle = context->GetBlobDataFromUUID(uuid);
245 DCHECK(!ContainsKey(blob_data_handle_map_, uuid));
246 blob_data_handle_map_[uuid] = std::make_pair(blob_data_handle.release(), 1);
247 return uuid;
250 void IndexedDBDispatcherHost::DropBlobData(const std::string& uuid) {
251 DCHECK_CURRENTLY_ON(BrowserThread::IO);
252 BlobDataHandleMap::iterator iter = blob_data_handle_map_.find(uuid);
253 if (iter != blob_data_handle_map_.end()) {
254 DCHECK_GE(iter->second.second, 1);
255 if (iter->second.second == 1) {
256 delete iter->second.first;
257 blob_data_handle_map_.erase(iter);
258 } else {
259 iter->second.second -= 1;
261 } else {
262 DLOG(FATAL) << "Failed to find blob UUID in map:" << uuid;
266 IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
267 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
268 return cursor_dispatcher_host_->map_.Lookup(ipc_cursor_id);
271 ::IndexedDBDatabaseMetadata IndexedDBDispatcherHost::ConvertMetadata(
272 const content::IndexedDBDatabaseMetadata& web_metadata) {
273 ::IndexedDBDatabaseMetadata metadata;
274 metadata.id = web_metadata.id;
275 metadata.name = web_metadata.name;
276 metadata.version = web_metadata.version;
277 metadata.int_version = web_metadata.int_version;
278 metadata.max_object_store_id = web_metadata.max_object_store_id;
280 for (const auto& iter : web_metadata.object_stores) {
281 const content::IndexedDBObjectStoreMetadata& web_store_metadata =
282 iter.second;
283 ::IndexedDBObjectStoreMetadata idb_store_metadata;
284 idb_store_metadata.id = web_store_metadata.id;
285 idb_store_metadata.name = web_store_metadata.name;
286 idb_store_metadata.key_path = web_store_metadata.key_path;
287 idb_store_metadata.auto_increment = web_store_metadata.auto_increment;
288 idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
290 for (const auto& index_iter : web_store_metadata.indexes) {
291 const content::IndexedDBIndexMetadata& web_index_metadata =
292 index_iter.second;
293 ::IndexedDBIndexMetadata idb_index_metadata;
294 idb_index_metadata.id = web_index_metadata.id;
295 idb_index_metadata.name = web_index_metadata.name;
296 idb_index_metadata.key_path = web_index_metadata.key_path;
297 idb_index_metadata.unique = web_index_metadata.unique;
298 idb_index_metadata.multi_entry = web_index_metadata.multi_entry;
299 idb_store_metadata.indexes.push_back(idb_index_metadata);
301 metadata.object_stores.push_back(idb_store_metadata);
303 return metadata;
306 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
307 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) {
308 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
309 base::FilePath indexed_db_path = indexed_db_context_->data_path();
311 GURL origin_url =
312 storage::GetOriginFromIdentifier(params.database_identifier);
314 Context()->GetIDBFactory()->GetDatabaseNames(
315 new IndexedDBCallbacks(
316 this, params.ipc_thread_id, params.ipc_callbacks_id),
317 origin_url,
318 indexed_db_path,
319 request_context_);
322 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
323 const IndexedDBHostMsg_FactoryOpen_Params& params) {
324 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
325 base::TimeTicks begin_time = base::TimeTicks::Now();
326 base::FilePath indexed_db_path = indexed_db_context_->data_path();
328 GURL origin_url =
329 storage::GetOriginFromIdentifier(params.database_identifier);
331 int64 host_transaction_id = HostTransactionId(params.transaction_id);
333 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
334 // created) if this origin is already over quota.
335 scoped_refptr<IndexedDBCallbacks> callbacks =
336 new IndexedDBCallbacks(this,
337 params.ipc_thread_id,
338 params.ipc_callbacks_id,
339 params.ipc_database_callbacks_id,
340 host_transaction_id,
341 origin_url);
342 callbacks->SetConnectionOpenStartTime(begin_time);
343 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
344 new IndexedDBDatabaseCallbacks(
345 this, params.ipc_thread_id, params.ipc_database_callbacks_id);
346 IndexedDBPendingConnection connection(callbacks,
347 database_callbacks,
348 ipc_process_id_,
349 host_transaction_id,
350 params.version);
351 DCHECK(request_context_);
352 Context()->GetIDBFactory()->Open(
353 params.name, connection, request_context_, origin_url, indexed_db_path);
356 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
357 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
358 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
359 GURL origin_url =
360 storage::GetOriginFromIdentifier(params.database_identifier);
361 base::FilePath indexed_db_path = indexed_db_context_->data_path();
362 DCHECK(request_context_);
363 Context()->GetIDBFactory()->DeleteDatabase(
364 params.name,
365 request_context_,
366 new IndexedDBCallbacks(
367 this, params.ipc_thread_id, params.ipc_callbacks_id),
368 origin_url,
369 indexed_db_path);
372 // OnPutHelper exists only to allow us to hop threads while holding a reference
373 // to the IndexedDBDispatcherHost.
374 void IndexedDBDispatcherHost::OnPutHelper(
375 const IndexedDBHostMsg_DatabasePut_Params& params,
376 std::vector<storage::BlobDataHandle*> handles) {
377 database_dispatcher_host_->OnPut(params, handles);
380 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
381 const std::vector<std::string>& uuids) {
382 DCHECK_CURRENTLY_ON(BrowserThread::IO);
383 for (const auto& uuid : uuids)
384 DropBlobData(uuid);
387 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
388 bool committed) {
389 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
390 if (!database_dispatcher_host_)
391 return;
392 TransactionIDToURLMap& transaction_url_map =
393 database_dispatcher_host_->transaction_url_map_;
394 TransactionIDToSizeMap& transaction_size_map =
395 database_dispatcher_host_->transaction_size_map_;
396 TransactionIDToDatabaseIDMap& transaction_database_map =
397 database_dispatcher_host_->transaction_database_map_;
398 if (committed)
399 Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
400 transaction_url_map.erase(host_transaction_id);
401 transaction_size_map.erase(host_transaction_id);
402 transaction_database_map.erase(host_transaction_id);
405 //////////////////////////////////////////////////////////////////////
406 // Helper templates.
409 template <typename ObjectType>
410 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
411 IDMap<ObjectType, IDMapOwnPointer>* map,
412 int32 ipc_return_object_id) {
413 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
414 ObjectType* return_object = map->Lookup(ipc_return_object_id);
415 if (!return_object) {
416 NOTREACHED() << "Uh oh, couldn't find object with id "
417 << ipc_return_object_id;
418 bad_message::ReceivedBadMessage(this, bad_message::IDBDH_GET_OR_TERMINATE);
420 return return_object;
423 template <typename ObjectType>
424 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
425 RefIDMap<ObjectType>* map,
426 int32 ipc_return_object_id) {
427 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
428 ObjectType* return_object = map->Lookup(ipc_return_object_id);
429 if (!return_object) {
430 NOTREACHED() << "Uh oh, couldn't find object with id "
431 << ipc_return_object_id;
432 bad_message::ReceivedBadMessage(this, bad_message::IDBDH_GET_OR_TERMINATE);
434 return return_object;
437 template <typename MapType>
438 void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) {
439 GetOrTerminateProcess(map, ipc_object_id);
440 map->Remove(ipc_object_id);
443 //////////////////////////////////////////////////////////////////////
444 // IndexedDBDispatcherHost::DatabaseDispatcherHost
447 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
448 IndexedDBDispatcherHost* parent)
449 : parent_(parent) {
450 map_.set_check_on_null_data(true);
453 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
454 // TODO(alecflett): uncomment these when we find the source of these leaks.
455 // DCHECK(transaction_size_map_.empty());
456 // DCHECK(transaction_url_map_.empty());
459 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
460 DCHECK(
461 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
462 // Abort outstanding transactions started by connections in the associated
463 // front-end to unblock later transactions. This should only occur on unclean
464 // (crash) or abrupt (process-kill) shutdowns.
465 for (TransactionIDToDatabaseIDMap::iterator iter =
466 transaction_database_map_.begin();
467 iter != transaction_database_map_.end();) {
468 int64 transaction_id = iter->first;
469 int32 ipc_database_id = iter->second;
470 ++iter;
471 IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
472 if (connection && connection->IsConnected()) {
473 connection->database()->Abort(
474 transaction_id,
475 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError));
478 DCHECK(transaction_database_map_.empty());
480 for (const auto& iter : database_url_map_) {
481 IndexedDBConnection* connection = map_.Lookup(iter.first);
482 if (connection && connection->IsConnected()) {
483 connection->Close();
484 parent_->Context()->ConnectionClosed(iter.second, connection);
489 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
490 const IPC::Message& message) {
491 DCHECK(
492 (message.type() == IndexedDBHostMsg_DatabasePut::ID ||
493 message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID) ||
494 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
496 bool handled = true;
497 IPC_BEGIN_MESSAGE_MAP(
498 IndexedDBDispatcherHost::DatabaseDispatcherHost, message)
499 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
500 OnCreateObjectStore)
501 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
502 OnDeleteObjectStore)
503 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
504 OnCreateTransaction)
505 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
506 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored,
507 OnVersionChangeIgnored)
508 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
509 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
510 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGetAll, OnGetAll)
511 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
512 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
513 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
514 OnSetIndexesReady)
515 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor)
516 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount)
517 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange)
518 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear)
519 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex)
520 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex)
521 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort)
522 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit)
523 IPC_MESSAGE_UNHANDLED(handled = false)
524 IPC_END_MESSAGE_MAP()
526 return handled;
529 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
530 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
531 DCHECK(
532 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
533 IndexedDBConnection* connection =
534 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
535 if (!connection || !connection->IsConnected())
536 return;
538 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
539 connection->database()->CreateObjectStore(host_transaction_id,
540 params.object_store_id,
541 params.name,
542 params.key_path,
543 params.auto_increment);
544 if (parent_->Context()->IsOverQuota(
545 database_url_map_[params.ipc_database_id])) {
546 connection->database()->Abort(
547 host_transaction_id,
548 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
552 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
553 int32 ipc_database_id,
554 int64 transaction_id,
555 int64 object_store_id) {
556 DCHECK(
557 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
558 IndexedDBConnection* connection =
559 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
560 if (!connection || !connection->IsConnected())
561 return;
563 connection->database()->DeleteObjectStore(
564 parent_->HostTransactionId(transaction_id), object_store_id);
567 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
568 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
569 DCHECK(
570 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
571 IndexedDBConnection* connection =
572 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
573 if (!connection || !connection->IsConnected())
574 return;
576 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
578 if (transaction_database_map_.find(host_transaction_id) !=
579 transaction_database_map_.end()) {
580 DLOG(ERROR) << "Duplicate host_transaction_id.";
581 return;
584 connection->database()->CreateTransaction(
585 host_transaction_id, connection, params.object_store_ids, params.mode);
586 transaction_database_map_[host_transaction_id] = params.ipc_database_id;
587 parent_->RegisterTransactionId(host_transaction_id,
588 database_url_map_[params.ipc_database_id]);
591 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
592 int32 ipc_database_id) {
593 DCHECK(
594 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
595 IndexedDBConnection* connection =
596 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
597 if (!connection || !connection->IsConnected())
598 return;
599 connection->Close();
602 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
603 int32 ipc_database_id) {
604 DCHECK(
605 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
606 IndexedDBConnection* connection =
607 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
608 if (!connection || !connection->IsConnected())
609 return;
610 connection->VersionChangeIgnored();
613 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
614 int32 ipc_object_id) {
615 DCHECK(
616 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
617 IndexedDBConnection* connection =
618 parent_->GetOrTerminateProcess(&map_, ipc_object_id);
619 if (!connection)
620 return;
621 if (connection->IsConnected())
622 connection->Close();
623 parent_->Context()
624 ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
625 database_url_map_.erase(ipc_object_id);
626 parent_->DestroyObject(&map_, ipc_object_id);
629 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
630 const IndexedDBHostMsg_DatabaseGet_Params& params) {
631 DCHECK(
632 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
633 IndexedDBConnection* connection =
634 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
635 if (!connection || !connection->IsConnected())
636 return;
638 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
639 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
640 connection->database()->Get(
641 parent_->HostTransactionId(params.transaction_id),
642 params.object_store_id,
643 params.index_id,
644 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
645 params.key_only,
646 callbacks);
649 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGetAll(
650 const IndexedDBHostMsg_DatabaseGetAll_Params& params) {
651 DCHECK(
652 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
653 IndexedDBConnection* connection =
654 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
655 if (!connection || !connection->IsConnected())
656 return;
658 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
659 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
660 connection->database()->GetAll(
661 parent_->HostTransactionId(params.transaction_id), params.object_store_id,
662 params.index_id, make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
663 params.key_only, params.max_count, callbacks);
666 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
667 const IndexedDBHostMsg_DatabasePut_Params& params) {
668 std::vector<storage::BlobDataHandle*> handles;
669 for (size_t i = 0; i < params.value.blob_or_file_info.size(); ++i) {
670 const IndexedDBMsg_BlobOrFileInfo& info = params.value.blob_or_file_info[i];
671 handles.push_back(parent_->blob_storage_context_->context()
672 ->GetBlobDataFromUUID(info.uuid)
673 .release());
675 parent_->indexed_db_context_->TaskRunner()->PostTask(
676 FROM_HERE,
677 base::Bind(
678 &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
681 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
682 const IndexedDBHostMsg_DatabasePut_Params& params,
683 std::vector<storage::BlobDataHandle*> handles) {
684 DCHECK(
685 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
687 ScopedVector<storage::BlobDataHandle> scoped_handles;
688 scoped_handles.swap(handles);
690 IndexedDBConnection* connection =
691 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
692 if (!connection || !connection->IsConnected())
693 return;
694 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
695 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
697 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
699 std::vector<IndexedDBBlobInfo> blob_info(
700 params.value.blob_or_file_info.size());
702 ChildProcessSecurityPolicyImpl* policy =
703 ChildProcessSecurityPolicyImpl::GetInstance();
705 for (size_t i = 0; i < params.value.blob_or_file_info.size(); ++i) {
706 const IndexedDBMsg_BlobOrFileInfo& info = params.value.blob_or_file_info[i];
707 if (info.is_file) {
708 base::FilePath path;
709 if (!info.file_path.empty()) {
710 path = base::FilePath::FromUTF16Unsafe(info.file_path);
711 if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
712 bad_message::ReceivedBadMessage(parent_,
713 bad_message::IDBDH_CAN_READ_FILE);
714 return;
717 blob_info[i] =
718 IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type);
719 if (info.size != static_cast<uint64_t>(-1)) {
720 blob_info[i].set_last_modified(
721 base::Time::FromDoubleT(info.last_modified));
722 blob_info[i].set_size(info.size);
724 } else {
725 blob_info[i] = IndexedDBBlobInfo(info.uuid, info.mime_type, info.size);
729 // TODO(alecflett): Avoid a copy here.
730 IndexedDBValue value;
731 value.bits = params.value.bits;
732 value.blob_info.swap(blob_info);
733 connection->database()->Put(host_transaction_id,
734 params.object_store_id,
735 &value,
736 &scoped_handles,
737 make_scoped_ptr(new IndexedDBKey(params.key)),
738 params.put_mode,
739 callbacks,
740 params.index_keys);
741 TransactionIDToSizeMap* map =
742 &parent_->database_dispatcher_host_->transaction_size_map_;
743 // Size can't be big enough to overflow because it represents the
744 // actual bytes passed through IPC.
745 (*map)[host_transaction_id] += params.value.bits.size();
748 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
749 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
750 DCHECK(
751 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
752 IndexedDBConnection* connection =
753 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
754 if (!connection || !connection->IsConnected())
755 return;
757 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
758 connection->database()->SetIndexKeys(
759 host_transaction_id,
760 params.object_store_id,
761 make_scoped_ptr(new IndexedDBKey(params.primary_key)),
762 params.index_keys);
765 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
766 int32 ipc_database_id,
767 int64 transaction_id,
768 int64 object_store_id,
769 const std::vector<int64>& index_ids) {
770 DCHECK(
771 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
772 IndexedDBConnection* connection =
773 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
774 if (!connection || !connection->IsConnected())
775 return;
777 connection->database()->SetIndexesReady(
778 parent_->HostTransactionId(transaction_id), object_store_id, index_ids);
781 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
782 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
783 DCHECK(
784 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
785 IndexedDBConnection* connection =
786 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
787 if (!connection || !connection->IsConnected())
788 return;
790 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
791 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1));
792 connection->database()->OpenCursor(
793 parent_->HostTransactionId(params.transaction_id),
794 params.object_store_id,
795 params.index_id,
796 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
797 params.direction,
798 params.key_only,
799 params.task_type,
800 callbacks);
803 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
804 const IndexedDBHostMsg_DatabaseCount_Params& params) {
805 DCHECK(
806 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
807 IndexedDBConnection* connection =
808 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
809 if (!connection || !connection->IsConnected())
810 return;
812 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
813 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
814 connection->database()->Count(
815 parent_->HostTransactionId(params.transaction_id),
816 params.object_store_id,
817 params.index_id,
818 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
819 callbacks);
822 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
823 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
824 DCHECK(
825 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
826 IndexedDBConnection* connection =
827 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
828 if (!connection || !connection->IsConnected())
829 return;
831 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
832 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
833 connection->database()->DeleteRange(
834 parent_->HostTransactionId(params.transaction_id),
835 params.object_store_id,
836 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
837 callbacks);
840 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
841 int32 ipc_thread_id,
842 int32 ipc_callbacks_id,
843 int32 ipc_database_id,
844 int64 transaction_id,
845 int64 object_store_id) {
846 DCHECK(
847 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
848 IndexedDBConnection* connection =
849 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
850 if (!connection || !connection->IsConnected())
851 return;
853 scoped_refptr<IndexedDBCallbacks> callbacks(
854 new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id));
856 connection->database()->Clear(
857 parent_->HostTransactionId(transaction_id), object_store_id, callbacks);
860 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
861 int32 ipc_database_id,
862 int64 transaction_id) {
863 DCHECK(
864 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
865 IndexedDBConnection* connection =
866 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
867 if (!connection || !connection->IsConnected())
868 return;
870 connection->database()->Abort(parent_->HostTransactionId(transaction_id));
873 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
874 int32 ipc_database_id,
875 int64 transaction_id) {
876 DCHECK(
877 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
878 IndexedDBConnection* connection =
879 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
880 if (!connection || !connection->IsConnected())
881 return;
883 int64 host_transaction_id = parent_->HostTransactionId(transaction_id);
884 int64 transaction_size = transaction_size_map_[host_transaction_id];
885 if (transaction_size &&
886 parent_->Context()->WouldBeOverQuota(
887 transaction_url_map_[host_transaction_id], transaction_size)) {
888 connection->database()->Abort(
889 host_transaction_id,
890 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
891 return;
894 connection->database()->Commit(host_transaction_id);
897 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
898 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
899 DCHECK(
900 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
901 IndexedDBConnection* connection =
902 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
903 if (!connection || !connection->IsConnected())
904 return;
906 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
907 connection->database()->CreateIndex(host_transaction_id,
908 params.object_store_id,
909 params.index_id,
910 params.name,
911 params.key_path,
912 params.unique,
913 params.multi_entry);
914 if (parent_->Context()->IsOverQuota(
915 database_url_map_[params.ipc_database_id])) {
916 connection->database()->Abort(
917 host_transaction_id,
918 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
922 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
923 int32 ipc_database_id,
924 int64 transaction_id,
925 int64 object_store_id,
926 int64 index_id) {
927 DCHECK(
928 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
929 IndexedDBConnection* connection =
930 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
931 if (!connection || !connection->IsConnected())
932 return;
934 connection->database()->DeleteIndex(
935 parent_->HostTransactionId(transaction_id), object_store_id, index_id);
938 //////////////////////////////////////////////////////////////////////
939 // IndexedDBDispatcherHost::CursorDispatcherHost
942 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
943 IndexedDBDispatcherHost* parent)
944 : parent_(parent) {
945 map_.set_check_on_null_data(true);
948 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
950 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
951 const IPC::Message& message) {
952 bool handled = true;
953 IPC_BEGIN_MESSAGE_MAP(
954 IndexedDBDispatcherHost::CursorDispatcherHost, message)
955 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance)
956 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
957 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch)
958 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset)
959 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
960 IPC_MESSAGE_UNHANDLED(handled = false)
961 IPC_END_MESSAGE_MAP()
963 DCHECK(
964 !handled ||
965 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
967 return handled;
970 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
971 int32 ipc_cursor_id,
972 int32 ipc_thread_id,
973 int32 ipc_callbacks_id,
974 uint32 count) {
975 DCHECK(
976 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
977 IndexedDBCursor* idb_cursor =
978 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
979 if (!idb_cursor)
980 return;
982 idb_cursor->Advance(
983 count,
984 new IndexedDBCallbacks(
985 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
988 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
989 int32 ipc_cursor_id,
990 int32 ipc_thread_id,
991 int32 ipc_callbacks_id,
992 const IndexedDBKey& key,
993 const IndexedDBKey& primary_key) {
994 DCHECK(
995 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
996 IndexedDBCursor* idb_cursor =
997 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
998 if (!idb_cursor)
999 return;
1001 idb_cursor->Continue(
1002 key.IsValid() ? make_scoped_ptr(new IndexedDBKey(key))
1003 : scoped_ptr<IndexedDBKey>(),
1004 primary_key.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key))
1005 : scoped_ptr<IndexedDBKey>(),
1006 new IndexedDBCallbacks(
1007 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
1010 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
1011 int32 ipc_cursor_id,
1012 int32 ipc_thread_id,
1013 int32 ipc_callbacks_id,
1014 int n) {
1015 DCHECK(
1016 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
1017 IndexedDBCursor* idb_cursor =
1018 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
1019 if (!idb_cursor)
1020 return;
1022 idb_cursor->PrefetchContinue(
1024 new IndexedDBCallbacks(
1025 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
1028 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
1029 int32 ipc_cursor_id,
1030 int used_prefetches,
1031 int unused_prefetches) {
1032 DCHECK(
1033 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
1034 IndexedDBCursor* idb_cursor =
1035 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
1036 if (!idb_cursor)
1037 return;
1039 leveldb::Status s =
1040 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
1041 // TODO(cmumford): Handle this error (crbug.com/363397)
1042 if (!s.ok())
1043 DLOG(ERROR) << "Unable to reset prefetch";
1046 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
1047 int32 ipc_object_id) {
1048 DCHECK(
1049 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
1050 parent_->DestroyObject(&map_, ipc_object_id);
1053 } // namespace content