Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_dispatcher_host.cc
blob21181fb90983727fa839b63f4105e4e9cad58afa
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 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 (content::IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator iter =
244 web_metadata.object_stores.begin();
245 iter != web_metadata.object_stores.end();
246 ++iter) {
247 const content::IndexedDBObjectStoreMetadata& web_store_metadata =
248 iter->second;
249 ::IndexedDBObjectStoreMetadata idb_store_metadata;
250 idb_store_metadata.id = web_store_metadata.id;
251 idb_store_metadata.name = web_store_metadata.name;
252 idb_store_metadata.keyPath = web_store_metadata.key_path;
253 idb_store_metadata.autoIncrement = web_store_metadata.auto_increment;
254 idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
256 for (content::IndexedDBObjectStoreMetadata::IndexMap::const_iterator
257 index_iter = web_store_metadata.indexes.begin();
258 index_iter != web_store_metadata.indexes.end();
259 ++index_iter) {
260 const content::IndexedDBIndexMetadata& web_index_metadata =
261 index_iter->second;
262 ::IndexedDBIndexMetadata idb_index_metadata;
263 idb_index_metadata.id = web_index_metadata.id;
264 idb_index_metadata.name = web_index_metadata.name;
265 idb_index_metadata.keyPath = web_index_metadata.key_path;
266 idb_index_metadata.unique = web_index_metadata.unique;
267 idb_index_metadata.multiEntry = web_index_metadata.multi_entry;
268 idb_store_metadata.indexes.push_back(idb_index_metadata);
270 metadata.object_stores.push_back(idb_store_metadata);
272 return metadata;
275 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
276 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) {
277 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
278 base::FilePath indexed_db_path = indexed_db_context_->data_path();
280 GURL origin_url =
281 storage::GetOriginFromIdentifier(params.database_identifier);
283 Context()->GetIDBFactory()->GetDatabaseNames(
284 new IndexedDBCallbacks(
285 this, params.ipc_thread_id, params.ipc_callbacks_id),
286 origin_url,
287 indexed_db_path,
288 request_context_);
291 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
292 const IndexedDBHostMsg_FactoryOpen_Params& params) {
293 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
294 base::TimeTicks begin_time = base::TimeTicks::Now();
295 base::FilePath indexed_db_path = indexed_db_context_->data_path();
297 GURL origin_url =
298 storage::GetOriginFromIdentifier(params.database_identifier);
300 int64 host_transaction_id = HostTransactionId(params.transaction_id);
302 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
303 // created) if this origin is already over quota.
304 scoped_refptr<IndexedDBCallbacks> callbacks =
305 new IndexedDBCallbacks(this,
306 params.ipc_thread_id,
307 params.ipc_callbacks_id,
308 params.ipc_database_callbacks_id,
309 host_transaction_id,
310 origin_url);
311 callbacks->SetConnectionOpenStartTime(begin_time);
312 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
313 new IndexedDBDatabaseCallbacks(
314 this, params.ipc_thread_id, params.ipc_database_callbacks_id);
315 IndexedDBPendingConnection connection(callbacks,
316 database_callbacks,
317 ipc_process_id_,
318 host_transaction_id,
319 params.version);
320 DCHECK(request_context_);
321 Context()->GetIDBFactory()->Open(
322 params.name, connection, request_context_, origin_url, indexed_db_path);
325 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
326 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
327 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
328 GURL origin_url =
329 storage::GetOriginFromIdentifier(params.database_identifier);
330 base::FilePath indexed_db_path = indexed_db_context_->data_path();
331 DCHECK(request_context_);
332 Context()->GetIDBFactory()->DeleteDatabase(
333 params.name,
334 request_context_,
335 new IndexedDBCallbacks(
336 this, params.ipc_thread_id, params.ipc_callbacks_id),
337 origin_url,
338 indexed_db_path);
341 // OnPutHelper exists only to allow us to hop threads while holding a reference
342 // to the IndexedDBDispatcherHost.
343 void IndexedDBDispatcherHost::OnPutHelper(
344 const IndexedDBHostMsg_DatabasePut_Params& params,
345 std::vector<storage::BlobDataHandle*> handles) {
346 database_dispatcher_host_->OnPut(params, handles);
349 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
350 const std::vector<std::string>& uuids) {
351 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
352 std::vector<std::string>::const_iterator iter;
353 for (iter = uuids.begin(); iter != uuids.end(); ++iter)
354 DropBlobDataHandle(*iter);
357 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
358 bool committed) {
359 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
360 if (!database_dispatcher_host_)
361 return;
362 TransactionIDToURLMap& transaction_url_map =
363 database_dispatcher_host_->transaction_url_map_;
364 TransactionIDToSizeMap& transaction_size_map =
365 database_dispatcher_host_->transaction_size_map_;
366 TransactionIDToDatabaseIDMap& transaction_database_map =
367 database_dispatcher_host_->transaction_database_map_;
368 if (committed)
369 Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
370 transaction_url_map.erase(host_transaction_id);
371 transaction_size_map.erase(host_transaction_id);
372 transaction_database_map.erase(host_transaction_id);
375 //////////////////////////////////////////////////////////////////////
376 // Helper templates.
379 template <typename ObjectType>
380 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
381 IDMap<ObjectType, IDMapOwnPointer>* map,
382 int32 ipc_return_object_id) {
383 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
384 ObjectType* return_object = map->Lookup(ipc_return_object_id);
385 if (!return_object) {
386 NOTREACHED() << "Uh oh, couldn't find object with id "
387 << ipc_return_object_id;
388 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
389 BadMessageReceived();
391 return return_object;
394 template <typename ObjectType>
395 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
396 RefIDMap<ObjectType>* map,
397 int32 ipc_return_object_id) {
398 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
399 ObjectType* return_object = map->Lookup(ipc_return_object_id);
400 if (!return_object) {
401 NOTREACHED() << "Uh oh, couldn't find object with id "
402 << ipc_return_object_id;
403 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
404 BadMessageReceived();
406 return return_object;
409 template <typename MapType>
410 void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) {
411 GetOrTerminateProcess(map, ipc_object_id);
412 map->Remove(ipc_object_id);
415 //////////////////////////////////////////////////////////////////////
416 // IndexedDBDispatcherHost::DatabaseDispatcherHost
419 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
420 IndexedDBDispatcherHost* parent)
421 : parent_(parent) {
422 map_.set_check_on_null_data(true);
425 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
426 // TODO(alecflett): uncomment these when we find the source of these leaks.
427 // DCHECK(transaction_size_map_.empty());
428 // DCHECK(transaction_url_map_.empty());
431 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
432 DCHECK(
433 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
434 // Abort outstanding transactions started by connections in the associated
435 // front-end to unblock later transactions. This should only occur on unclean
436 // (crash) or abrupt (process-kill) shutdowns.
437 for (TransactionIDToDatabaseIDMap::iterator iter =
438 transaction_database_map_.begin();
439 iter != transaction_database_map_.end();) {
440 int64 transaction_id = iter->first;
441 int32 ipc_database_id = iter->second;
442 ++iter;
443 IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
444 if (connection && connection->IsConnected()) {
445 connection->database()->Abort(
446 transaction_id,
447 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError));
450 DCHECK(transaction_database_map_.empty());
452 for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin();
453 iter != database_url_map_.end();
454 iter++) {
455 IndexedDBConnection* connection = map_.Lookup(iter->first);
456 if (connection && connection->IsConnected()) {
457 connection->Close();
458 parent_->Context()->ConnectionClosed(iter->second, connection);
463 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
464 const IPC::Message& message) {
466 DCHECK(
467 (message.type() == IndexedDBHostMsg_DatabasePut::ID) ||
468 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
470 bool handled = true;
471 IPC_BEGIN_MESSAGE_MAP(
472 IndexedDBDispatcherHost::DatabaseDispatcherHost, message)
473 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
474 OnCreateObjectStore)
475 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
476 OnDeleteObjectStore)
477 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
478 OnCreateTransaction)
479 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
480 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored,
481 OnVersionChangeIgnored)
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::OnVersionChangeIgnored(
576 int32 ipc_database_id) {
577 DCHECK(
578 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
579 IndexedDBConnection* connection =
580 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
581 if (!connection || !connection->IsConnected())
582 return;
583 connection->VersionChangeIgnored();
586 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
587 int32 ipc_object_id) {
588 DCHECK(
589 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
590 IndexedDBConnection* connection = map_.Lookup(ipc_object_id);
591 if (connection->IsConnected())
592 connection->Close();
593 parent_->Context()
594 ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
595 database_url_map_.erase(ipc_object_id);
596 parent_->DestroyObject(&map_, ipc_object_id);
599 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
600 const IndexedDBHostMsg_DatabaseGet_Params& params) {
601 DCHECK(
602 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
603 IndexedDBConnection* connection =
604 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
605 if (!connection || !connection->IsConnected())
606 return;
608 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
609 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
610 connection->database()->Get(
611 parent_->HostTransactionId(params.transaction_id),
612 params.object_store_id,
613 params.index_id,
614 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
615 params.key_only,
616 callbacks);
619 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
620 const IndexedDBHostMsg_DatabasePut_Params& params) {
621 std::vector<storage::BlobDataHandle*> handles;
622 for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
623 const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
624 handles.push_back(parent_->blob_storage_context_->context()
625 ->GetBlobDataFromUUID(info.uuid)
626 .release());
628 parent_->indexed_db_context_->TaskRunner()->PostTask(
629 FROM_HERE,
630 base::Bind(
631 &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
634 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
635 const IndexedDBHostMsg_DatabasePut_Params& params,
636 std::vector<storage::BlobDataHandle*> handles) {
637 DCHECK(
638 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
640 ScopedVector<storage::BlobDataHandle> scoped_handles;
641 scoped_handles.swap(handles);
643 IndexedDBConnection* connection =
644 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
645 if (!connection || !connection->IsConnected())
646 return;
647 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
648 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
650 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
652 std::vector<IndexedDBBlobInfo> blob_info(params.blob_or_file_info.size());
654 ChildProcessSecurityPolicyImpl* policy =
655 ChildProcessSecurityPolicyImpl::GetInstance();
657 for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
658 const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
659 if (info.is_file) {
660 base::FilePath path = base::FilePath::FromUTF16Unsafe(info.file_path);
661 if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
662 parent_->BadMessageReceived();
663 return;
665 blob_info[i] =
666 IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type);
667 if (info.size != static_cast<uint64_t>(-1)) {
668 blob_info[i].set_last_modified(
669 base::Time::FromDoubleT(info.last_modified));
670 blob_info[i].set_size(info.size);
672 } else {
673 blob_info[i] = IndexedDBBlobInfo(info.uuid, info.mime_type, info.size);
677 // TODO(alecflett): Avoid a copy here.
678 IndexedDBValue value;
679 value.bits = params.value;
680 value.blob_info.swap(blob_info);
681 connection->database()->Put(host_transaction_id,
682 params.object_store_id,
683 &value,
684 &scoped_handles,
685 make_scoped_ptr(new IndexedDBKey(params.key)),
686 params.put_mode,
687 callbacks,
688 params.index_keys);
689 TransactionIDToSizeMap* map =
690 &parent_->database_dispatcher_host_->transaction_size_map_;
691 // Size can't be big enough to overflow because it represents the
692 // actual bytes passed through IPC.
693 (*map)[host_transaction_id] += params.value.size();
696 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
697 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
698 DCHECK(
699 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
700 IndexedDBConnection* connection =
701 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
702 if (!connection || !connection->IsConnected())
703 return;
705 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
706 connection->database()->SetIndexKeys(
707 host_transaction_id,
708 params.object_store_id,
709 make_scoped_ptr(new IndexedDBKey(params.primary_key)),
710 params.index_keys);
713 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
714 int32 ipc_database_id,
715 int64 transaction_id,
716 int64 object_store_id,
717 const std::vector<int64>& index_ids) {
718 DCHECK(
719 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
720 IndexedDBConnection* connection =
721 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
722 if (!connection || !connection->IsConnected())
723 return;
725 connection->database()->SetIndexesReady(
726 parent_->HostTransactionId(transaction_id), object_store_id, index_ids);
729 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
730 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
731 DCHECK(
732 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
733 IndexedDBConnection* connection =
734 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
735 if (!connection || !connection->IsConnected())
736 return;
738 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
739 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1));
740 connection->database()->OpenCursor(
741 parent_->HostTransactionId(params.transaction_id),
742 params.object_store_id,
743 params.index_id,
744 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
745 params.direction,
746 params.key_only,
747 params.task_type,
748 callbacks);
751 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
752 const IndexedDBHostMsg_DatabaseCount_Params& params) {
753 DCHECK(
754 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
755 IndexedDBConnection* connection =
756 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
757 if (!connection || !connection->IsConnected())
758 return;
760 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
761 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
762 connection->database()->Count(
763 parent_->HostTransactionId(params.transaction_id),
764 params.object_store_id,
765 params.index_id,
766 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
767 callbacks);
770 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
771 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
772 DCHECK(
773 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
774 IndexedDBConnection* connection =
775 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
776 if (!connection || !connection->IsConnected())
777 return;
779 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
780 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
781 connection->database()->DeleteRange(
782 parent_->HostTransactionId(params.transaction_id),
783 params.object_store_id,
784 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
785 callbacks);
788 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
789 int32 ipc_thread_id,
790 int32 ipc_callbacks_id,
791 int32 ipc_database_id,
792 int64 transaction_id,
793 int64 object_store_id) {
794 DCHECK(
795 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
796 IndexedDBConnection* connection =
797 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
798 if (!connection || !connection->IsConnected())
799 return;
801 scoped_refptr<IndexedDBCallbacks> callbacks(
802 new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id));
804 connection->database()->Clear(
805 parent_->HostTransactionId(transaction_id), object_store_id, callbacks);
808 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
809 int32 ipc_database_id,
810 int64 transaction_id) {
811 DCHECK(
812 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
813 IndexedDBConnection* connection =
814 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
815 if (!connection || !connection->IsConnected())
816 return;
818 connection->database()->Abort(parent_->HostTransactionId(transaction_id));
821 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
822 int32 ipc_database_id,
823 int64 transaction_id) {
824 DCHECK(
825 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
826 IndexedDBConnection* connection =
827 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
828 if (!connection || !connection->IsConnected())
829 return;
831 int64 host_transaction_id = parent_->HostTransactionId(transaction_id);
832 int64 transaction_size = transaction_size_map_[host_transaction_id];
833 if (transaction_size &&
834 parent_->Context()->WouldBeOverQuota(
835 transaction_url_map_[host_transaction_id], transaction_size)) {
836 connection->database()->Abort(
837 host_transaction_id,
838 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
839 return;
842 connection->database()->Commit(host_transaction_id);
845 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
846 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
847 DCHECK(
848 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
849 IndexedDBConnection* connection =
850 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
851 if (!connection || !connection->IsConnected())
852 return;
854 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
855 connection->database()->CreateIndex(host_transaction_id,
856 params.object_store_id,
857 params.index_id,
858 params.name,
859 params.key_path,
860 params.unique,
861 params.multi_entry);
862 if (parent_->Context()->IsOverQuota(
863 database_url_map_[params.ipc_database_id])) {
864 connection->database()->Abort(
865 host_transaction_id,
866 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
870 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
871 int32 ipc_database_id,
872 int64 transaction_id,
873 int64 object_store_id,
874 int64 index_id) {
875 DCHECK(
876 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
877 IndexedDBConnection* connection =
878 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
879 if (!connection || !connection->IsConnected())
880 return;
882 connection->database()->DeleteIndex(
883 parent_->HostTransactionId(transaction_id), object_store_id, index_id);
886 //////////////////////////////////////////////////////////////////////
887 // IndexedDBDispatcherHost::CursorDispatcherHost
890 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
891 IndexedDBDispatcherHost* parent)
892 : parent_(parent) {
893 map_.set_check_on_null_data(true);
896 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
898 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
899 const IPC::Message& message) {
900 bool handled = true;
901 IPC_BEGIN_MESSAGE_MAP(
902 IndexedDBDispatcherHost::CursorDispatcherHost, message)
903 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance)
904 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
905 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch)
906 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset)
907 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
908 IPC_MESSAGE_UNHANDLED(handled = false)
909 IPC_END_MESSAGE_MAP()
911 DCHECK(
912 !handled ||
913 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
915 return handled;
918 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
919 int32 ipc_cursor_id,
920 int32 ipc_thread_id,
921 int32 ipc_callbacks_id,
922 uint32 count) {
923 DCHECK(
924 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
925 IndexedDBCursor* idb_cursor =
926 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
927 if (!idb_cursor)
928 return;
930 idb_cursor->Advance(
931 count,
932 new IndexedDBCallbacks(
933 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
936 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
937 int32 ipc_cursor_id,
938 int32 ipc_thread_id,
939 int32 ipc_callbacks_id,
940 const IndexedDBKey& key,
941 const IndexedDBKey& primary_key) {
942 DCHECK(
943 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
944 IndexedDBCursor* idb_cursor =
945 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
946 if (!idb_cursor)
947 return;
949 idb_cursor->Continue(
950 key.IsValid() ? make_scoped_ptr(new IndexedDBKey(key))
951 : scoped_ptr<IndexedDBKey>(),
952 primary_key.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key))
953 : scoped_ptr<IndexedDBKey>(),
954 new IndexedDBCallbacks(
955 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
958 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
959 int32 ipc_cursor_id,
960 int32 ipc_thread_id,
961 int32 ipc_callbacks_id,
962 int n) {
963 DCHECK(
964 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
965 IndexedDBCursor* idb_cursor =
966 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
967 if (!idb_cursor)
968 return;
970 idb_cursor->PrefetchContinue(
972 new IndexedDBCallbacks(
973 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
976 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
977 int32 ipc_cursor_id,
978 int used_prefetches,
979 int unused_prefetches) {
980 DCHECK(
981 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
982 IndexedDBCursor* idb_cursor =
983 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
984 if (!idb_cursor)
985 return;
987 leveldb::Status s =
988 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
989 // TODO(cmumford): Handle this error (crbug.com/363397)
990 if (!s.ok())
991 DLOG(ERROR) << "Unable to reset prefetch";
994 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
995 int32 ipc_object_id) {
996 DCHECK(
997 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
998 parent_->DestroyObject(&map_, ipc_object_id);
1001 } // namespace content