cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_dispatcher_host.cc
blob3584f03e83a40003ae70a158cc8afdc307c25558
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 "storage/browser/blob/blob_storage_context.h"
30 #include "storage/browser/database/database_util.h"
31 #include "storage/common/database/database_identifier.h"
32 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
33 #include "url/gurl.h"
35 using storage::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_.get());
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_.get());
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 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
129 return false;
131 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread() ||
132 message.type() == IndexedDBHostMsg_DatabasePut::ID);
134 bool handled = database_dispatcher_host_->OnMessageReceived(message) ||
135 cursor_dispatcher_host_->OnMessageReceived(message);
137 if (!handled) {
138 handled = true;
139 IPC_BEGIN_MESSAGE_MAP(IndexedDBDispatcherHost, message)
140 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames,
141 OnIDBFactoryGetDatabaseNames)
142 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen)
143 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase,
144 OnIDBFactoryDeleteDatabase)
145 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_AckReceivedBlobs, OnAckReceivedBlobs)
146 IPC_MESSAGE_UNHANDLED(handled = false)
147 IPC_END_MESSAGE_MAP()
149 return handled;
152 int32 IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) {
153 if (!cursor_dispatcher_host_) {
154 return 0;
156 return cursor_dispatcher_host_->map_.Add(cursor);
159 int32 IndexedDBDispatcherHost::Add(IndexedDBConnection* connection,
160 int32 ipc_thread_id,
161 const GURL& origin_url) {
162 if (!database_dispatcher_host_) {
163 connection->Close();
164 delete connection;
165 return -1;
167 int32 ipc_database_id = database_dispatcher_host_->map_.Add(connection);
168 Context()->ConnectionOpened(origin_url, connection);
169 database_dispatcher_host_->database_url_map_[ipc_database_id] = origin_url;
170 return ipc_database_id;
173 void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id,
174 const GURL& url) {
175 if (!database_dispatcher_host_)
176 return;
177 database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url;
180 int64 IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id) {
181 // Inject the renderer process id into the transaction id, to
182 // uniquely identify this transaction, and effectively bind it to
183 // the renderer that initiated it. The lower 32 bits of
184 // transaction_id are guaranteed to be unique within that renderer.
185 base::ProcessId pid = peer_pid();
186 DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits";
187 COMPILE_ASSERT(sizeof(base::ProcessId) <= sizeof(int32),
188 Process_ID_must_fit_in_32_bits);
190 return transaction_id | (static_cast<uint64>(pid) << 32);
193 int64 IndexedDBDispatcherHost::RendererTransactionId(
194 int64 host_transaction_id) {
195 DCHECK(host_transaction_id >> 32 == peer_pid())
196 << "Invalid renderer target for transaction id";
197 return host_transaction_id & 0xffffffff;
200 // static
201 uint32 IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
202 int64 host_transaction_id) {
203 return host_transaction_id & 0xffffffff;
206 // static
207 uint32 IndexedDBDispatcherHost::TransactionIdToProcessId(
208 int64 host_transaction_id) {
209 return (host_transaction_id >> 32) & 0xffffffff;
212 void IndexedDBDispatcherHost::HoldBlobDataHandle(
213 const std::string& uuid,
214 scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
215 DCHECK(!ContainsKey(blob_data_handle_map_, uuid));
216 blob_data_handle_map_[uuid] = blob_data_handle.release();
219 void IndexedDBDispatcherHost::DropBlobDataHandle(const std::string& uuid) {
220 BlobDataHandleMap::iterator iter = blob_data_handle_map_.find(uuid);
221 if (iter != blob_data_handle_map_.end()) {
222 delete iter->second;
223 blob_data_handle_map_.erase(iter);
224 } else {
225 DLOG(FATAL) << "Failed to find blob UUID in map:" << uuid;
229 IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
230 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
231 return cursor_dispatcher_host_->map_.Lookup(ipc_cursor_id);
234 ::IndexedDBDatabaseMetadata IndexedDBDispatcherHost::ConvertMetadata(
235 const content::IndexedDBDatabaseMetadata& web_metadata) {
236 ::IndexedDBDatabaseMetadata metadata;
237 metadata.id = web_metadata.id;
238 metadata.name = web_metadata.name;
239 metadata.version = web_metadata.version;
240 metadata.int_version = web_metadata.int_version;
241 metadata.max_object_store_id = web_metadata.max_object_store_id;
243 for (const auto& iter : web_metadata.object_stores) {
244 const content::IndexedDBObjectStoreMetadata& web_store_metadata =
245 iter.second;
246 ::IndexedDBObjectStoreMetadata idb_store_metadata;
247 idb_store_metadata.id = web_store_metadata.id;
248 idb_store_metadata.name = web_store_metadata.name;
249 idb_store_metadata.keyPath = web_store_metadata.key_path;
250 idb_store_metadata.autoIncrement = web_store_metadata.auto_increment;
251 idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
253 for (const auto& index_iter : web_store_metadata.indexes) {
254 const content::IndexedDBIndexMetadata& web_index_metadata =
255 index_iter.second;
256 ::IndexedDBIndexMetadata idb_index_metadata;
257 idb_index_metadata.id = web_index_metadata.id;
258 idb_index_metadata.name = web_index_metadata.name;
259 idb_index_metadata.keyPath = web_index_metadata.key_path;
260 idb_index_metadata.unique = web_index_metadata.unique;
261 idb_index_metadata.multiEntry = web_index_metadata.multi_entry;
262 idb_store_metadata.indexes.push_back(idb_index_metadata);
264 metadata.object_stores.push_back(idb_store_metadata);
266 return metadata;
269 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
270 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) {
271 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
272 base::FilePath indexed_db_path = indexed_db_context_->data_path();
274 GURL origin_url =
275 storage::GetOriginFromIdentifier(params.database_identifier);
277 Context()->GetIDBFactory()->GetDatabaseNames(
278 new IndexedDBCallbacks(
279 this, params.ipc_thread_id, params.ipc_callbacks_id),
280 origin_url,
281 indexed_db_path,
282 request_context_);
285 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
286 const IndexedDBHostMsg_FactoryOpen_Params& params) {
287 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
288 base::TimeTicks begin_time = base::TimeTicks::Now();
289 base::FilePath indexed_db_path = indexed_db_context_->data_path();
291 GURL origin_url =
292 storage::GetOriginFromIdentifier(params.database_identifier);
294 int64 host_transaction_id = HostTransactionId(params.transaction_id);
296 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
297 // created) if this origin is already over quota.
298 scoped_refptr<IndexedDBCallbacks> callbacks =
299 new IndexedDBCallbacks(this,
300 params.ipc_thread_id,
301 params.ipc_callbacks_id,
302 params.ipc_database_callbacks_id,
303 host_transaction_id,
304 origin_url);
305 callbacks->SetConnectionOpenStartTime(begin_time);
306 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
307 new IndexedDBDatabaseCallbacks(
308 this, params.ipc_thread_id, params.ipc_database_callbacks_id);
309 IndexedDBPendingConnection connection(callbacks,
310 database_callbacks,
311 ipc_process_id_,
312 host_transaction_id,
313 params.version);
314 DCHECK(request_context_);
315 Context()->GetIDBFactory()->Open(
316 params.name, connection, request_context_, origin_url, indexed_db_path);
319 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
320 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
321 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
322 GURL origin_url =
323 storage::GetOriginFromIdentifier(params.database_identifier);
324 base::FilePath indexed_db_path = indexed_db_context_->data_path();
325 DCHECK(request_context_);
326 Context()->GetIDBFactory()->DeleteDatabase(
327 params.name,
328 request_context_,
329 new IndexedDBCallbacks(
330 this, params.ipc_thread_id, params.ipc_callbacks_id),
331 origin_url,
332 indexed_db_path);
335 // OnPutHelper exists only to allow us to hop threads while holding a reference
336 // to the IndexedDBDispatcherHost.
337 void IndexedDBDispatcherHost::OnPutHelper(
338 const IndexedDBHostMsg_DatabasePut_Params& params,
339 std::vector<storage::BlobDataHandle*> handles) {
340 database_dispatcher_host_->OnPut(params, handles);
343 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
344 const std::vector<std::string>& uuids) {
345 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
346 for (const auto& uuid : uuids)
347 DropBlobDataHandle(uuid);
350 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
351 bool committed) {
352 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
353 if (!database_dispatcher_host_)
354 return;
355 TransactionIDToURLMap& transaction_url_map =
356 database_dispatcher_host_->transaction_url_map_;
357 TransactionIDToSizeMap& transaction_size_map =
358 database_dispatcher_host_->transaction_size_map_;
359 TransactionIDToDatabaseIDMap& transaction_database_map =
360 database_dispatcher_host_->transaction_database_map_;
361 if (committed)
362 Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
363 transaction_url_map.erase(host_transaction_id);
364 transaction_size_map.erase(host_transaction_id);
365 transaction_database_map.erase(host_transaction_id);
368 //////////////////////////////////////////////////////////////////////
369 // Helper templates.
372 template <typename ObjectType>
373 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
374 IDMap<ObjectType, IDMapOwnPointer>* map,
375 int32 ipc_return_object_id) {
376 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
377 ObjectType* return_object = map->Lookup(ipc_return_object_id);
378 if (!return_object) {
379 NOTREACHED() << "Uh oh, couldn't find object with id "
380 << ipc_return_object_id;
381 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
382 BadMessageReceived();
384 return return_object;
387 template <typename ObjectType>
388 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
389 RefIDMap<ObjectType>* map,
390 int32 ipc_return_object_id) {
391 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
392 ObjectType* return_object = map->Lookup(ipc_return_object_id);
393 if (!return_object) {
394 NOTREACHED() << "Uh oh, couldn't find object with id "
395 << ipc_return_object_id;
396 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
397 BadMessageReceived();
399 return return_object;
402 template <typename MapType>
403 void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) {
404 GetOrTerminateProcess(map, ipc_object_id);
405 map->Remove(ipc_object_id);
408 //////////////////////////////////////////////////////////////////////
409 // IndexedDBDispatcherHost::DatabaseDispatcherHost
412 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
413 IndexedDBDispatcherHost* parent)
414 : parent_(parent) {
415 map_.set_check_on_null_data(true);
418 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
419 // TODO(alecflett): uncomment these when we find the source of these leaks.
420 // DCHECK(transaction_size_map_.empty());
421 // DCHECK(transaction_url_map_.empty());
424 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
425 DCHECK(
426 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
427 // Abort outstanding transactions started by connections in the associated
428 // front-end to unblock later transactions. This should only occur on unclean
429 // (crash) or abrupt (process-kill) shutdowns.
430 for (TransactionIDToDatabaseIDMap::iterator iter =
431 transaction_database_map_.begin();
432 iter != transaction_database_map_.end();) {
433 int64 transaction_id = iter->first;
434 int32 ipc_database_id = iter->second;
435 ++iter;
436 IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
437 if (connection && connection->IsConnected()) {
438 connection->database()->Abort(
439 transaction_id,
440 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError));
443 DCHECK(transaction_database_map_.empty());
445 for (const auto& iter : database_url_map_) {
446 IndexedDBConnection* connection = map_.Lookup(iter.first);
447 if (connection && connection->IsConnected()) {
448 connection->Close();
449 parent_->Context()->ConnectionClosed(iter.second, connection);
454 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
455 const IPC::Message& message) {
457 DCHECK(
458 (message.type() == IndexedDBHostMsg_DatabasePut::ID) ||
459 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
461 bool handled = true;
462 IPC_BEGIN_MESSAGE_MAP(
463 IndexedDBDispatcherHost::DatabaseDispatcherHost, message)
464 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
465 OnCreateObjectStore)
466 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
467 OnDeleteObjectStore)
468 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
469 OnCreateTransaction)
470 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
471 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored,
472 OnVersionChangeIgnored)
473 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
474 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
475 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
476 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
477 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
478 OnSetIndexesReady)
479 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor)
480 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount)
481 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange)
482 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear)
483 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex)
484 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex)
485 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort)
486 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit)
487 IPC_MESSAGE_UNHANDLED(handled = false)
488 IPC_END_MESSAGE_MAP()
490 return handled;
493 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
494 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
495 DCHECK(
496 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
497 IndexedDBConnection* connection =
498 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
499 if (!connection || !connection->IsConnected())
500 return;
502 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
503 connection->database()->CreateObjectStore(host_transaction_id,
504 params.object_store_id,
505 params.name,
506 params.key_path,
507 params.auto_increment);
508 if (parent_->Context()->IsOverQuota(
509 database_url_map_[params.ipc_database_id])) {
510 connection->database()->Abort(
511 host_transaction_id,
512 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
516 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
517 int32 ipc_database_id,
518 int64 transaction_id,
519 int64 object_store_id) {
520 DCHECK(
521 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
522 IndexedDBConnection* connection =
523 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
524 if (!connection || !connection->IsConnected())
525 return;
527 connection->database()->DeleteObjectStore(
528 parent_->HostTransactionId(transaction_id), object_store_id);
531 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
532 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
533 DCHECK(
534 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
535 IndexedDBConnection* connection =
536 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
537 if (!connection || !connection->IsConnected())
538 return;
540 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
542 if (transaction_database_map_.find(host_transaction_id) !=
543 transaction_database_map_.end()) {
544 DLOG(ERROR) << "Duplicate host_transaction_id.";
545 return;
548 connection->database()->CreateTransaction(
549 host_transaction_id, connection, params.object_store_ids, params.mode);
550 transaction_database_map_[host_transaction_id] = params.ipc_database_id;
551 parent_->RegisterTransactionId(host_transaction_id,
552 database_url_map_[params.ipc_database_id]);
555 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
556 int32 ipc_database_id) {
557 DCHECK(
558 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
559 IndexedDBConnection* connection =
560 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
561 if (!connection || !connection->IsConnected())
562 return;
563 connection->Close();
566 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
567 int32 ipc_database_id) {
568 DCHECK(
569 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
570 IndexedDBConnection* connection =
571 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
572 if (!connection || !connection->IsConnected())
573 return;
574 connection->VersionChangeIgnored();
577 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
578 int32 ipc_object_id) {
579 DCHECK(
580 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
581 IndexedDBConnection* connection = map_.Lookup(ipc_object_id);
582 if (connection->IsConnected())
583 connection->Close();
584 parent_->Context()
585 ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
586 database_url_map_.erase(ipc_object_id);
587 parent_->DestroyObject(&map_, ipc_object_id);
590 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
591 const IndexedDBHostMsg_DatabaseGet_Params& params) {
592 DCHECK(
593 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
594 IndexedDBConnection* connection =
595 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
596 if (!connection || !connection->IsConnected())
597 return;
599 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
600 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
601 connection->database()->Get(
602 parent_->HostTransactionId(params.transaction_id),
603 params.object_store_id,
604 params.index_id,
605 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
606 params.key_only,
607 callbacks);
610 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
611 const IndexedDBHostMsg_DatabasePut_Params& params) {
612 std::vector<storage::BlobDataHandle*> handles;
613 for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
614 const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
615 handles.push_back(parent_->blob_storage_context_->context()
616 ->GetBlobDataFromUUID(info.uuid)
617 .release());
619 parent_->indexed_db_context_->TaskRunner()->PostTask(
620 FROM_HERE,
621 base::Bind(
622 &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
625 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
626 const IndexedDBHostMsg_DatabasePut_Params& params,
627 std::vector<storage::BlobDataHandle*> handles) {
628 DCHECK(
629 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
631 ScopedVector<storage::BlobDataHandle> scoped_handles;
632 scoped_handles.swap(handles);
634 IndexedDBConnection* connection =
635 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
636 if (!connection || !connection->IsConnected())
637 return;
638 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
639 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
641 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
643 std::vector<IndexedDBBlobInfo> blob_info(params.blob_or_file_info.size());
645 ChildProcessSecurityPolicyImpl* policy =
646 ChildProcessSecurityPolicyImpl::GetInstance();
648 for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
649 const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
650 if (info.is_file) {
651 base::FilePath path = base::FilePath::FromUTF16Unsafe(info.file_path);
652 if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
653 parent_->BadMessageReceived();
654 return;
656 blob_info[i] =
657 IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type);
658 if (info.size != static_cast<uint64_t>(-1)) {
659 blob_info[i].set_last_modified(
660 base::Time::FromDoubleT(info.last_modified));
661 blob_info[i].set_size(info.size);
663 } else {
664 blob_info[i] = IndexedDBBlobInfo(info.uuid, info.mime_type, info.size);
668 // TODO(alecflett): Avoid a copy here.
669 IndexedDBValue value;
670 value.bits = params.value;
671 value.blob_info.swap(blob_info);
672 connection->database()->Put(host_transaction_id,
673 params.object_store_id,
674 &value,
675 &scoped_handles,
676 make_scoped_ptr(new IndexedDBKey(params.key)),
677 params.put_mode,
678 callbacks,
679 params.index_keys);
680 TransactionIDToSizeMap* map =
681 &parent_->database_dispatcher_host_->transaction_size_map_;
682 // Size can't be big enough to overflow because it represents the
683 // actual bytes passed through IPC.
684 (*map)[host_transaction_id] += params.value.size();
687 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
688 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
689 DCHECK(
690 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
691 IndexedDBConnection* connection =
692 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
693 if (!connection || !connection->IsConnected())
694 return;
696 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
697 connection->database()->SetIndexKeys(
698 host_transaction_id,
699 params.object_store_id,
700 make_scoped_ptr(new IndexedDBKey(params.primary_key)),
701 params.index_keys);
704 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
705 int32 ipc_database_id,
706 int64 transaction_id,
707 int64 object_store_id,
708 const std::vector<int64>& index_ids) {
709 DCHECK(
710 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
711 IndexedDBConnection* connection =
712 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
713 if (!connection || !connection->IsConnected())
714 return;
716 connection->database()->SetIndexesReady(
717 parent_->HostTransactionId(transaction_id), object_store_id, index_ids);
720 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
721 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
722 DCHECK(
723 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
724 IndexedDBConnection* connection =
725 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
726 if (!connection || !connection->IsConnected())
727 return;
729 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
730 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1));
731 connection->database()->OpenCursor(
732 parent_->HostTransactionId(params.transaction_id),
733 params.object_store_id,
734 params.index_id,
735 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
736 params.direction,
737 params.key_only,
738 params.task_type,
739 callbacks);
742 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
743 const IndexedDBHostMsg_DatabaseCount_Params& params) {
744 DCHECK(
745 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
746 IndexedDBConnection* connection =
747 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
748 if (!connection || !connection->IsConnected())
749 return;
751 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
752 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
753 connection->database()->Count(
754 parent_->HostTransactionId(params.transaction_id),
755 params.object_store_id,
756 params.index_id,
757 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
758 callbacks);
761 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
762 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
763 DCHECK(
764 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
765 IndexedDBConnection* connection =
766 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
767 if (!connection || !connection->IsConnected())
768 return;
770 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
771 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
772 connection->database()->DeleteRange(
773 parent_->HostTransactionId(params.transaction_id),
774 params.object_store_id,
775 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
776 callbacks);
779 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
780 int32 ipc_thread_id,
781 int32 ipc_callbacks_id,
782 int32 ipc_database_id,
783 int64 transaction_id,
784 int64 object_store_id) {
785 DCHECK(
786 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
787 IndexedDBConnection* connection =
788 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
789 if (!connection || !connection->IsConnected())
790 return;
792 scoped_refptr<IndexedDBCallbacks> callbacks(
793 new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id));
795 connection->database()->Clear(
796 parent_->HostTransactionId(transaction_id), object_store_id, callbacks);
799 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
800 int32 ipc_database_id,
801 int64 transaction_id) {
802 DCHECK(
803 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
804 IndexedDBConnection* connection =
805 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
806 if (!connection || !connection->IsConnected())
807 return;
809 connection->database()->Abort(parent_->HostTransactionId(transaction_id));
812 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
813 int32 ipc_database_id,
814 int64 transaction_id) {
815 DCHECK(
816 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
817 IndexedDBConnection* connection =
818 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
819 if (!connection || !connection->IsConnected())
820 return;
822 int64 host_transaction_id = parent_->HostTransactionId(transaction_id);
823 int64 transaction_size = transaction_size_map_[host_transaction_id];
824 if (transaction_size &&
825 parent_->Context()->WouldBeOverQuota(
826 transaction_url_map_[host_transaction_id], transaction_size)) {
827 connection->database()->Abort(
828 host_transaction_id,
829 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
830 return;
833 connection->database()->Commit(host_transaction_id);
836 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
837 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
838 DCHECK(
839 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
840 IndexedDBConnection* connection =
841 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
842 if (!connection || !connection->IsConnected())
843 return;
845 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
846 connection->database()->CreateIndex(host_transaction_id,
847 params.object_store_id,
848 params.index_id,
849 params.name,
850 params.key_path,
851 params.unique,
852 params.multi_entry);
853 if (parent_->Context()->IsOverQuota(
854 database_url_map_[params.ipc_database_id])) {
855 connection->database()->Abort(
856 host_transaction_id,
857 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
861 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
862 int32 ipc_database_id,
863 int64 transaction_id,
864 int64 object_store_id,
865 int64 index_id) {
866 DCHECK(
867 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
868 IndexedDBConnection* connection =
869 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
870 if (!connection || !connection->IsConnected())
871 return;
873 connection->database()->DeleteIndex(
874 parent_->HostTransactionId(transaction_id), object_store_id, index_id);
877 //////////////////////////////////////////////////////////////////////
878 // IndexedDBDispatcherHost::CursorDispatcherHost
881 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
882 IndexedDBDispatcherHost* parent)
883 : parent_(parent) {
884 map_.set_check_on_null_data(true);
887 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
889 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
890 const IPC::Message& message) {
891 bool handled = true;
892 IPC_BEGIN_MESSAGE_MAP(
893 IndexedDBDispatcherHost::CursorDispatcherHost, message)
894 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance)
895 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
896 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch)
897 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset)
898 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
899 IPC_MESSAGE_UNHANDLED(handled = false)
900 IPC_END_MESSAGE_MAP()
902 DCHECK(
903 !handled ||
904 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
906 return handled;
909 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
910 int32 ipc_cursor_id,
911 int32 ipc_thread_id,
912 int32 ipc_callbacks_id,
913 uint32 count) {
914 DCHECK(
915 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
916 IndexedDBCursor* idb_cursor =
917 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
918 if (!idb_cursor)
919 return;
921 idb_cursor->Advance(
922 count,
923 new IndexedDBCallbacks(
924 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
927 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
928 int32 ipc_cursor_id,
929 int32 ipc_thread_id,
930 int32 ipc_callbacks_id,
931 const IndexedDBKey& key,
932 const IndexedDBKey& primary_key) {
933 DCHECK(
934 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
935 IndexedDBCursor* idb_cursor =
936 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
937 if (!idb_cursor)
938 return;
940 idb_cursor->Continue(
941 key.IsValid() ? make_scoped_ptr(new IndexedDBKey(key))
942 : scoped_ptr<IndexedDBKey>(),
943 primary_key.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key))
944 : scoped_ptr<IndexedDBKey>(),
945 new IndexedDBCallbacks(
946 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
949 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
950 int32 ipc_cursor_id,
951 int32 ipc_thread_id,
952 int32 ipc_callbacks_id,
953 int n) {
954 DCHECK(
955 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
956 IndexedDBCursor* idb_cursor =
957 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
958 if (!idb_cursor)
959 return;
961 idb_cursor->PrefetchContinue(
963 new IndexedDBCallbacks(
964 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
967 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
968 int32 ipc_cursor_id,
969 int used_prefetches,
970 int unused_prefetches) {
971 DCHECK(
972 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
973 IndexedDBCursor* idb_cursor =
974 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
975 if (!idb_cursor)
976 return;
978 leveldb::Status s =
979 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
980 // TODO(cmumford): Handle this error (crbug.com/363397)
981 if (!s.ok())
982 DLOG(ERROR) << "Unable to reset prefetch";
985 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
986 int32 ipc_object_id) {
987 DCHECK(
988 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
989 parent_->DestroyObject(&map_, ipc_object_id);
992 } // namespace content