1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/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"
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
;
40 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
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(
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(
89 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts
, this));
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();
127 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message
& message
) {
128 if (IPC_MESSAGE_CLASS(message
) != IndexedDBMsgStart
)
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
);
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()
152 int32
IndexedDBDispatcherHost::Add(IndexedDBCursor
* cursor
) {
153 if (!cursor_dispatcher_host_
) {
156 return cursor_dispatcher_host_
->map_
.Add(cursor
);
159 int32
IndexedDBDispatcherHost::Add(IndexedDBConnection
* connection
,
161 const GURL
& origin_url
) {
162 if (!database_dispatcher_host_
) {
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
,
175 if (!database_dispatcher_host_
)
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;
201 uint32
IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
202 int64 host_transaction_id
) {
203 return host_transaction_id
& 0xffffffff;
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()) {
223 blob_data_handle_map_
.erase(iter
);
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();
247 const content::IndexedDBObjectStoreMetadata
& web_store_metadata
=
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();
260 const content::IndexedDBIndexMetadata
& web_index_metadata
=
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
);
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();
281 storage::GetOriginFromIdentifier(params
.database_identifier
);
283 Context()->GetIDBFactory()->GetDatabaseNames(
284 new IndexedDBCallbacks(
285 this, params
.ipc_thread_id
, params
.ipc_callbacks_id
),
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();
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
,
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
,
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());
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(
335 new IndexedDBCallbacks(
336 this, params
.ipc_thread_id
, params
.ipc_callbacks_id
),
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
,
359 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
360 if (!database_dispatcher_host_
)
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_
;
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 //////////////////////////////////////////////////////////////////////
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
)
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() {
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
;
443 IndexedDBConnection
* connection
= map_
.Lookup(ipc_database_id
);
444 if (connection
&& connection
->IsConnected()) {
445 connection
->database()->Abort(
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();
455 IndexedDBConnection
* connection
= map_
.Lookup(iter
->first
);
456 if (connection
&& connection
->IsConnected()) {
458 parent_
->Context()->ConnectionClosed(iter
->second
, connection
);
463 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
464 const IPC::Message
& message
) {
467 (message
.type() == IndexedDBHostMsg_DatabasePut::ID
) ||
468 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
471 IPC_BEGIN_MESSAGE_MAP(
472 IndexedDBDispatcherHost::DatabaseDispatcherHost
, message
)
473 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore
,
475 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore
,
477 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction
,
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
,
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()
502 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
503 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params
& params
) {
505 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
506 IndexedDBConnection
* connection
=
507 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
508 if (!connection
|| !connection
->IsConnected())
511 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
512 connection
->database()->CreateObjectStore(host_transaction_id
,
513 params
.object_store_id
,
516 params
.auto_increment
);
517 if (parent_
->Context()->IsOverQuota(
518 database_url_map_
[params
.ipc_database_id
])) {
519 connection
->database()->Abort(
521 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
525 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
526 int32 ipc_database_id
,
527 int64 transaction_id
,
528 int64 object_store_id
) {
530 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
531 IndexedDBConnection
* connection
=
532 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
533 if (!connection
|| !connection
->IsConnected())
536 connection
->database()->DeleteObjectStore(
537 parent_
->HostTransactionId(transaction_id
), object_store_id
);
540 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
541 const IndexedDBHostMsg_DatabaseCreateTransaction_Params
& params
) {
543 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
544 IndexedDBConnection
* connection
=
545 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
546 if (!connection
|| !connection
->IsConnected())
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.";
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
) {
567 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
568 IndexedDBConnection
* connection
=
569 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
570 if (!connection
|| !connection
->IsConnected())
575 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
576 int32 ipc_database_id
) {
578 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
579 IndexedDBConnection
* connection
=
580 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
581 if (!connection
|| !connection
->IsConnected())
583 connection
->VersionChangeIgnored();
586 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
587 int32 ipc_object_id
) {
589 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
590 IndexedDBConnection
* connection
= map_
.Lookup(ipc_object_id
);
591 if (connection
->IsConnected())
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
) {
602 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
603 IndexedDBConnection
* connection
=
604 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
605 if (!connection
|| !connection
->IsConnected())
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
,
614 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
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
)
628 parent_
->indexed_db_context_
->TaskRunner()->PostTask(
631 &IndexedDBDispatcherHost::OnPutHelper
, parent_
, params
, handles
));
634 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
635 const IndexedDBHostMsg_DatabasePut_Params
& params
,
636 std::vector
<storage::BlobDataHandle
*> handles
) {
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())
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
];
660 base::FilePath path
= base::FilePath::FromUTF16Unsafe(info
.file_path
);
661 if (!policy
->CanReadFile(parent_
->ipc_process_id_
, path
)) {
662 parent_
->BadMessageReceived();
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
);
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
,
685 make_scoped_ptr(new IndexedDBKey(params
.key
)),
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
) {
699 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
700 IndexedDBConnection
* connection
=
701 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
702 if (!connection
|| !connection
->IsConnected())
705 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
706 connection
->database()->SetIndexKeys(
708 params
.object_store_id
,
709 make_scoped_ptr(new IndexedDBKey(params
.primary_key
)),
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
) {
719 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
720 IndexedDBConnection
* connection
=
721 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
722 if (!connection
|| !connection
->IsConnected())
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
) {
732 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
733 IndexedDBConnection
* connection
=
734 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
735 if (!connection
|| !connection
->IsConnected())
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
,
744 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
751 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
752 const IndexedDBHostMsg_DatabaseCount_Params
& params
) {
754 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
755 IndexedDBConnection
* connection
=
756 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
757 if (!connection
|| !connection
->IsConnected())
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
,
766 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
770 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
771 const IndexedDBHostMsg_DatabaseDeleteRange_Params
& params
) {
773 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
774 IndexedDBConnection
* connection
=
775 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
776 if (!connection
|| !connection
->IsConnected())
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
)),
788 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
790 int32 ipc_callbacks_id
,
791 int32 ipc_database_id
,
792 int64 transaction_id
,
793 int64 object_store_id
) {
795 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
796 IndexedDBConnection
* connection
=
797 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
798 if (!connection
|| !connection
->IsConnected())
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
) {
812 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
813 IndexedDBConnection
* connection
=
814 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
815 if (!connection
|| !connection
->IsConnected())
818 connection
->database()->Abort(parent_
->HostTransactionId(transaction_id
));
821 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
822 int32 ipc_database_id
,
823 int64 transaction_id
) {
825 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
826 IndexedDBConnection
* connection
=
827 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
828 if (!connection
|| !connection
->IsConnected())
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(
838 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
842 connection
->database()->Commit(host_transaction_id
);
845 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
846 const IndexedDBHostMsg_DatabaseCreateIndex_Params
& params
) {
848 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
849 IndexedDBConnection
* connection
=
850 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
851 if (!connection
|| !connection
->IsConnected())
854 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
855 connection
->database()->CreateIndex(host_transaction_id
,
856 params
.object_store_id
,
862 if (parent_
->Context()->IsOverQuota(
863 database_url_map_
[params
.ipc_database_id
])) {
864 connection
->database()->Abort(
866 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
870 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
871 int32 ipc_database_id
,
872 int64 transaction_id
,
873 int64 object_store_id
,
876 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
877 IndexedDBConnection
* connection
=
878 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
879 if (!connection
|| !connection
->IsConnected())
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
)
893 map_
.set_check_on_null_data(true);
896 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
898 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
899 const IPC::Message
& message
) {
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()
913 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
918 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
921 int32 ipc_callbacks_id
,
924 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
925 IndexedDBCursor
* idb_cursor
=
926 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
932 new IndexedDBCallbacks(
933 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
936 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
939 int32 ipc_callbacks_id
,
940 const IndexedDBKey
& key
,
941 const IndexedDBKey
& primary_key
) {
943 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
944 IndexedDBCursor
* idb_cursor
=
945 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
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(
961 int32 ipc_callbacks_id
,
964 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
965 IndexedDBCursor
* idb_cursor
=
966 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
970 idb_cursor
->PrefetchContinue(
972 new IndexedDBCallbacks(
973 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
976 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
979 int unused_prefetches
) {
981 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
982 IndexedDBCursor
* idb_cursor
=
983 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
988 idb_cursor
->PrefetchReset(used_prefetches
, unused_prefetches
);
989 // TODO(cmumford): Handle this error (crbug.com/363397)
991 DLOG(ERROR
) << "Unable to reset prefetch";
994 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
995 int32 ipc_object_id
) {
997 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
998 parent_
->DestroyObject(&map_
, ipc_object_id
);
1001 } // namespace content