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 webkit_database::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_
);
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_
);
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 bool* message_was_ok
) {
129 if (IPC_MESSAGE_CLASS(message
) != IndexedDBMsgStart
)
132 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread() ||
133 message
.type() == IndexedDBHostMsg_DatabasePut::ID
);
136 database_dispatcher_host_
->OnMessageReceived(message
, message_was_ok
) ||
137 cursor_dispatcher_host_
->OnMessageReceived(message
, message_was_ok
);
141 IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost
, message
, *message_was_ok
)
142 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames
,
143 OnIDBFactoryGetDatabaseNames
)
144 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen
, OnIDBFactoryOpen
)
145 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase
,
146 OnIDBFactoryDeleteDatabase
)
147 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_AckReceivedBlobs
, OnAckReceivedBlobs
)
148 IPC_MESSAGE_UNHANDLED(handled
= false)
149 IPC_END_MESSAGE_MAP()
154 int32
IndexedDBDispatcherHost::Add(IndexedDBCursor
* cursor
) {
155 if (!cursor_dispatcher_host_
) {
158 return cursor_dispatcher_host_
->map_
.Add(cursor
);
161 int32
IndexedDBDispatcherHost::Add(IndexedDBConnection
* connection
,
163 const GURL
& origin_url
) {
164 if (!database_dispatcher_host_
) {
169 int32 ipc_database_id
= database_dispatcher_host_
->map_
.Add(connection
);
170 Context()->ConnectionOpened(origin_url
, connection
);
171 database_dispatcher_host_
->database_url_map_
[ipc_database_id
] = origin_url
;
172 return ipc_database_id
;
175 void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id
,
177 if (!database_dispatcher_host_
)
179 database_dispatcher_host_
->transaction_url_map_
[host_transaction_id
] = url
;
182 int64
IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id
) {
183 // Inject the renderer process id into the transaction id, to
184 // uniquely identify this transaction, and effectively bind it to
185 // the renderer that initiated it. The lower 32 bits of
186 // transaction_id are guaranteed to be unique within that renderer.
187 base::ProcessId pid
= peer_pid();
188 DCHECK(!(transaction_id
>> 32)) << "Transaction ids can only be 32 bits";
189 COMPILE_ASSERT(sizeof(base::ProcessId
) <= sizeof(int32
),
190 Process_ID_must_fit_in_32_bits
);
192 return transaction_id
| (static_cast<uint64
>(pid
) << 32);
195 int64
IndexedDBDispatcherHost::RendererTransactionId(
196 int64 host_transaction_id
) {
197 DCHECK(host_transaction_id
>> 32 == peer_pid())
198 << "Invalid renderer target for transaction id";
199 return host_transaction_id
& 0xffffffff;
203 uint32
IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
204 int64 host_transaction_id
) {
205 return host_transaction_id
& 0xffffffff;
209 uint32
IndexedDBDispatcherHost::TransactionIdToProcessId(
210 int64 host_transaction_id
) {
211 return (host_transaction_id
>> 32) & 0xffffffff;
214 void IndexedDBDispatcherHost::HoldBlobDataHandle(
215 const std::string
& uuid
,
216 scoped_ptr
<webkit_blob::BlobDataHandle
>& blob_data_handle
) {
217 DCHECK(!ContainsKey(blob_data_handle_map_
, uuid
));
218 blob_data_handle_map_
[uuid
] = blob_data_handle
.release();
221 void IndexedDBDispatcherHost::DropBlobDataHandle(const std::string
& uuid
) {
222 BlobDataHandleMap::iterator iter
= blob_data_handle_map_
.find(uuid
);
223 if (iter
!= blob_data_handle_map_
.end()) {
225 blob_data_handle_map_
.erase(iter
);
227 DLOG(FATAL
) << "Failed to find blob UUID in map:" << uuid
;
231 IndexedDBCursor
* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id
) {
232 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
233 return cursor_dispatcher_host_
->map_
.Lookup(ipc_cursor_id
);
236 ::IndexedDBDatabaseMetadata
IndexedDBDispatcherHost::ConvertMetadata(
237 const content::IndexedDBDatabaseMetadata
& web_metadata
) {
238 ::IndexedDBDatabaseMetadata metadata
;
239 metadata
.id
= web_metadata
.id
;
240 metadata
.name
= web_metadata
.name
;
241 metadata
.version
= web_metadata
.version
;
242 metadata
.int_version
= web_metadata
.int_version
;
243 metadata
.max_object_store_id
= web_metadata
.max_object_store_id
;
245 for (content::IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator iter
=
246 web_metadata
.object_stores
.begin();
247 iter
!= web_metadata
.object_stores
.end();
250 const content::IndexedDBObjectStoreMetadata
& web_store_metadata
=
252 ::IndexedDBObjectStoreMetadata idb_store_metadata
;
253 idb_store_metadata
.id
= web_store_metadata
.id
;
254 idb_store_metadata
.name
= web_store_metadata
.name
;
255 idb_store_metadata
.keyPath
= web_store_metadata
.key_path
;
256 idb_store_metadata
.autoIncrement
= web_store_metadata
.auto_increment
;
257 idb_store_metadata
.max_index_id
= web_store_metadata
.max_index_id
;
259 for (content::IndexedDBObjectStoreMetadata::IndexMap::const_iterator
260 index_iter
= web_store_metadata
.indexes
.begin();
261 index_iter
!= web_store_metadata
.indexes
.end();
263 const content::IndexedDBIndexMetadata
& web_index_metadata
=
265 ::IndexedDBIndexMetadata idb_index_metadata
;
266 idb_index_metadata
.id
= web_index_metadata
.id
;
267 idb_index_metadata
.name
= web_index_metadata
.name
;
268 idb_index_metadata
.keyPath
= web_index_metadata
.key_path
;
269 idb_index_metadata
.unique
= web_index_metadata
.unique
;
270 idb_index_metadata
.multiEntry
= web_index_metadata
.multi_entry
;
271 idb_store_metadata
.indexes
.push_back(idb_index_metadata
);
273 metadata
.object_stores
.push_back(idb_store_metadata
);
278 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
279 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params
& params
) {
280 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
281 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
284 webkit_database::GetOriginFromIdentifier(params
.database_identifier
);
286 Context()->GetIDBFactory()->GetDatabaseNames(
287 new IndexedDBCallbacks(
288 this, params
.ipc_thread_id
, params
.ipc_callbacks_id
),
294 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
295 const IndexedDBHostMsg_FactoryOpen_Params
& params
) {
296 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
297 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
300 webkit_database::GetOriginFromIdentifier(params
.database_identifier
);
302 int64 host_transaction_id
= HostTransactionId(params
.transaction_id
);
304 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
305 // created) if this origin is already over quota.
306 scoped_refptr
<IndexedDBCallbacks
> callbacks
=
307 new IndexedDBCallbacks(this,
308 params
.ipc_thread_id
,
309 params
.ipc_callbacks_id
,
310 params
.ipc_database_callbacks_id
,
313 scoped_refptr
<IndexedDBDatabaseCallbacks
> database_callbacks
=
314 new IndexedDBDatabaseCallbacks(
315 this, params
.ipc_thread_id
, params
.ipc_database_callbacks_id
);
316 IndexedDBPendingConnection
connection(callbacks
,
321 DCHECK(request_context_
);
322 Context()->GetIDBFactory()->Open(
323 params
.name
, connection
, request_context_
, origin_url
, indexed_db_path
);
326 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
327 const IndexedDBHostMsg_FactoryDeleteDatabase_Params
& params
) {
328 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
330 webkit_database::GetOriginFromIdentifier(params
.database_identifier
);
331 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
332 DCHECK(request_context_
);
333 Context()->GetIDBFactory()->DeleteDatabase(
336 new IndexedDBCallbacks(
337 this, params
.ipc_thread_id
, params
.ipc_callbacks_id
),
342 // OnPutHelper exists only to allow us to hop threads while holding a reference
343 // to the IndexedDBDispatcherHost.
344 void IndexedDBDispatcherHost::OnPutHelper(
345 const IndexedDBHostMsg_DatabasePut_Params
& params
,
346 std::vector
<webkit_blob::BlobDataHandle
*> handles
) {
347 database_dispatcher_host_
->OnPut(params
, handles
);
350 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
351 const std::vector
<std::string
>& uuids
) {
352 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
353 std::vector
<std::string
>::const_iterator iter
;
354 for (iter
= uuids
.begin(); iter
!= uuids
.end(); ++iter
)
355 DropBlobDataHandle(*iter
);
358 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id
,
360 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
361 if (!database_dispatcher_host_
)
363 TransactionIDToURLMap
& transaction_url_map
=
364 database_dispatcher_host_
->transaction_url_map_
;
365 TransactionIDToSizeMap
& transaction_size_map
=
366 database_dispatcher_host_
->transaction_size_map_
;
367 TransactionIDToDatabaseIDMap
& transaction_database_map
=
368 database_dispatcher_host_
->transaction_database_map_
;
370 Context()->TransactionComplete(transaction_url_map
[host_transaction_id
]);
371 transaction_url_map
.erase(host_transaction_id
);
372 transaction_size_map
.erase(host_transaction_id
);
373 transaction_database_map
.erase(host_transaction_id
);
376 //////////////////////////////////////////////////////////////////////
380 template <typename ObjectType
>
381 ObjectType
* IndexedDBDispatcherHost::GetOrTerminateProcess(
382 IDMap
<ObjectType
, IDMapOwnPointer
>* map
,
383 int32 ipc_return_object_id
) {
384 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
385 ObjectType
* return_object
= map
->Lookup(ipc_return_object_id
);
386 if (!return_object
) {
387 NOTREACHED() << "Uh oh, couldn't find object with id "
388 << ipc_return_object_id
;
389 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
390 BadMessageReceived();
392 return return_object
;
395 template <typename ObjectType
>
396 ObjectType
* IndexedDBDispatcherHost::GetOrTerminateProcess(
397 RefIDMap
<ObjectType
>* map
,
398 int32 ipc_return_object_id
) {
399 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
400 ObjectType
* return_object
= map
->Lookup(ipc_return_object_id
);
401 if (!return_object
) {
402 NOTREACHED() << "Uh oh, couldn't find object with id "
403 << ipc_return_object_id
;
404 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
405 BadMessageReceived();
407 return return_object
;
410 template <typename MapType
>
411 void IndexedDBDispatcherHost::DestroyObject(MapType
* map
, int32 ipc_object_id
) {
412 GetOrTerminateProcess(map
, ipc_object_id
);
413 map
->Remove(ipc_object_id
);
416 //////////////////////////////////////////////////////////////////////
417 // IndexedDBDispatcherHost::DatabaseDispatcherHost
420 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
421 IndexedDBDispatcherHost
* parent
)
423 map_
.set_check_on_null_data(true);
426 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
427 // TODO(alecflett): uncomment these when we find the source of these leaks.
428 // DCHECK(transaction_size_map_.empty());
429 // DCHECK(transaction_url_map_.empty());
432 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
434 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
435 // Abort outstanding transactions started by connections in the associated
436 // front-end to unblock later transactions. This should only occur on unclean
437 // (crash) or abrupt (process-kill) shutdowns.
438 for (TransactionIDToDatabaseIDMap::iterator iter
=
439 transaction_database_map_
.begin();
440 iter
!= transaction_database_map_
.end();) {
441 int64 transaction_id
= iter
->first
;
442 int32 ipc_database_id
= iter
->second
;
444 IndexedDBConnection
* connection
= map_
.Lookup(ipc_database_id
);
445 if (connection
&& connection
->IsConnected()) {
446 connection
->database()->Abort(
448 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError
));
451 DCHECK(transaction_database_map_
.empty());
453 for (WebIDBObjectIDToURLMap::iterator iter
= database_url_map_
.begin();
454 iter
!= database_url_map_
.end();
456 IndexedDBConnection
* connection
= map_
.Lookup(iter
->first
);
457 if (connection
&& connection
->IsConnected()) {
459 parent_
->Context()->ConnectionClosed(iter
->second
, connection
);
464 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
465 const IPC::Message
& message
,
469 (message
.type() == IndexedDBHostMsg_DatabasePut::ID
) ||
470 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
473 IPC_BEGIN_MESSAGE_MAP_EX(
474 IndexedDBDispatcherHost::DatabaseDispatcherHost
, message
, *msg_is_ok
)
475 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore
,
477 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore
,
479 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction
,
481 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose
, OnClose
)
482 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed
, OnDestroyed
)
483 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet
, OnGet
)
484 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut
, OnPutWrapper
)
485 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys
, OnSetIndexKeys
)
486 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady
,
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::OnDestroyed(
576 int32 ipc_object_id
) {
578 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
579 IndexedDBConnection
* connection
= map_
.Lookup(ipc_object_id
);
580 if (connection
->IsConnected())
583 ->ConnectionClosed(database_url_map_
[ipc_object_id
], connection
);
584 database_url_map_
.erase(ipc_object_id
);
585 parent_
->DestroyObject(&map_
, ipc_object_id
);
588 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
589 const IndexedDBHostMsg_DatabaseGet_Params
& params
) {
591 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
592 IndexedDBConnection
* connection
=
593 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
594 if (!connection
|| !connection
->IsConnected())
597 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
598 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
599 connection
->database()->Get(
600 parent_
->HostTransactionId(params
.transaction_id
),
601 params
.object_store_id
,
603 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
608 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
609 const IndexedDBHostMsg_DatabasePut_Params
& params
) {
610 std::vector
<webkit_blob::BlobDataHandle
*> handles
;
611 for (size_t i
= 0; i
< params
.blob_or_file_info
.size(); ++i
) {
612 const IndexedDBMsg_BlobOrFileInfo
& info
= params
.blob_or_file_info
[i
];
613 handles
.push_back(parent_
->blob_storage_context_
->context()
614 ->GetBlobDataFromUUID(info
.uuid
)
617 parent_
->indexed_db_context_
->TaskRunner()->PostTask(
620 &IndexedDBDispatcherHost::OnPutHelper
, parent_
, params
, handles
));
623 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
624 const IndexedDBHostMsg_DatabasePut_Params
& params
,
625 std::vector
<webkit_blob::BlobDataHandle
*> handles
) {
628 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
630 ScopedVector
<webkit_blob::BlobDataHandle
> scoped_handles
;
631 scoped_handles
.swap(handles
);
633 IndexedDBConnection
* connection
=
634 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
635 if (!connection
|| !connection
->IsConnected())
637 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
638 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
640 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
642 std::vector
<IndexedDBBlobInfo
> blob_info(params
.blob_or_file_info
.size());
644 ChildProcessSecurityPolicyImpl
* policy
=
645 ChildProcessSecurityPolicyImpl::GetInstance();
647 for (size_t i
= 0; i
< params
.blob_or_file_info
.size(); ++i
) {
648 const IndexedDBMsg_BlobOrFileInfo
& info
= params
.blob_or_file_info
[i
];
650 base::FilePath path
= base::FilePath::FromUTF16Unsafe(info
.file_path
);
651 if (!policy
->CanReadFile(parent_
->ipc_process_id_
, path
)) {
652 parent_
->BadMessageReceived();
656 IndexedDBBlobInfo(info
.uuid
, path
, info
.file_name
, info
.mime_type
);
658 blob_info
[i
] = IndexedDBBlobInfo(info
.uuid
, info
.mime_type
, info
.size
);
662 // TODO(alecflett): Avoid a copy here.
663 IndexedDBValue value
;
664 value
.bits
= params
.value
;
665 value
.blob_info
.swap(blob_info
);
666 connection
->database()->Put(
668 params
.object_store_id
,
671 make_scoped_ptr(new IndexedDBKey(params
.key
)),
672 static_cast<IndexedDBDatabase::PutMode
>(params
.put_mode
),
675 TransactionIDToSizeMap
* map
=
676 &parent_
->database_dispatcher_host_
->transaction_size_map_
;
677 // Size can't be big enough to overflow because it represents the
678 // actual bytes passed through IPC.
679 (*map
)[host_transaction_id
] += params
.value
.size();
682 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
683 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params
& params
) {
685 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
686 IndexedDBConnection
* connection
=
687 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
688 if (!connection
|| !connection
->IsConnected())
691 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
692 connection
->database()->SetIndexKeys(
694 params
.object_store_id
,
695 make_scoped_ptr(new IndexedDBKey(params
.primary_key
)),
699 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
700 int32 ipc_database_id
,
701 int64 transaction_id
,
702 int64 object_store_id
,
703 const std::vector
<int64
>& index_ids
) {
705 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
706 IndexedDBConnection
* connection
=
707 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
708 if (!connection
|| !connection
->IsConnected())
711 connection
->database()->SetIndexesReady(
712 parent_
->HostTransactionId(transaction_id
), object_store_id
, index_ids
);
715 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
716 const IndexedDBHostMsg_DatabaseOpenCursor_Params
& params
) {
718 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
719 IndexedDBConnection
* connection
=
720 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
721 if (!connection
|| !connection
->IsConnected())
724 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
725 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
, -1));
726 connection
->database()->OpenCursor(
727 parent_
->HostTransactionId(params
.transaction_id
),
728 params
.object_store_id
,
730 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
731 static_cast<indexed_db::CursorDirection
>(params
.direction
),
733 static_cast<IndexedDBDatabase::TaskType
>(params
.task_type
),
737 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
738 const IndexedDBHostMsg_DatabaseCount_Params
& params
) {
740 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
741 IndexedDBConnection
* connection
=
742 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
743 if (!connection
|| !connection
->IsConnected())
746 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
747 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
748 connection
->database()->Count(
749 parent_
->HostTransactionId(params
.transaction_id
),
750 params
.object_store_id
,
752 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
756 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
757 const IndexedDBHostMsg_DatabaseDeleteRange_Params
& params
) {
759 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
760 IndexedDBConnection
* connection
=
761 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
762 if (!connection
|| !connection
->IsConnected())
765 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
766 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
767 connection
->database()->DeleteRange(
768 parent_
->HostTransactionId(params
.transaction_id
),
769 params
.object_store_id
,
770 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
774 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
776 int32 ipc_callbacks_id
,
777 int32 ipc_database_id
,
778 int64 transaction_id
,
779 int64 object_store_id
) {
781 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
782 IndexedDBConnection
* connection
=
783 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
784 if (!connection
|| !connection
->IsConnected())
787 scoped_refptr
<IndexedDBCallbacks
> callbacks(
788 new IndexedDBCallbacks(parent_
, ipc_thread_id
, ipc_callbacks_id
));
790 connection
->database()->Clear(
791 parent_
->HostTransactionId(transaction_id
), object_store_id
, callbacks
);
794 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
795 int32 ipc_database_id
,
796 int64 transaction_id
) {
798 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
799 IndexedDBConnection
* connection
=
800 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
801 if (!connection
|| !connection
->IsConnected())
804 connection
->database()->Abort(parent_
->HostTransactionId(transaction_id
));
807 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
808 int32 ipc_database_id
,
809 int64 transaction_id
) {
811 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
812 IndexedDBConnection
* connection
=
813 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
814 if (!connection
|| !connection
->IsConnected())
817 int64 host_transaction_id
= parent_
->HostTransactionId(transaction_id
);
818 int64 transaction_size
= transaction_size_map_
[host_transaction_id
];
819 if (transaction_size
&&
820 parent_
->Context()->WouldBeOverQuota(
821 transaction_url_map_
[host_transaction_id
], transaction_size
)) {
822 connection
->database()->Abort(
824 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
828 connection
->database()->Commit(host_transaction_id
);
831 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
832 const IndexedDBHostMsg_DatabaseCreateIndex_Params
& params
) {
834 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
835 IndexedDBConnection
* connection
=
836 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
837 if (!connection
|| !connection
->IsConnected())
840 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
841 connection
->database()->CreateIndex(host_transaction_id
,
842 params
.object_store_id
,
848 if (parent_
->Context()->IsOverQuota(
849 database_url_map_
[params
.ipc_database_id
])) {
850 connection
->database()->Abort(
852 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
856 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
857 int32 ipc_database_id
,
858 int64 transaction_id
,
859 int64 object_store_id
,
862 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
863 IndexedDBConnection
* connection
=
864 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
865 if (!connection
|| !connection
->IsConnected())
868 connection
->database()->DeleteIndex(
869 parent_
->HostTransactionId(transaction_id
), object_store_id
, index_id
);
872 //////////////////////////////////////////////////////////////////////
873 // IndexedDBDispatcherHost::CursorDispatcherHost
876 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
877 IndexedDBDispatcherHost
* parent
)
879 map_
.set_check_on_null_data(true);
882 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
884 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
885 const IPC::Message
& message
,
888 IPC_BEGIN_MESSAGE_MAP_EX(
889 IndexedDBDispatcherHost::CursorDispatcherHost
, message
, *msg_is_ok
)
890 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance
, OnAdvance
)
891 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue
, OnContinue
)
892 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch
, OnPrefetch
)
893 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset
, OnPrefetchReset
)
894 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed
, OnDestroyed
)
895 IPC_MESSAGE_UNHANDLED(handled
= false)
896 IPC_END_MESSAGE_MAP()
900 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
905 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
908 int32 ipc_callbacks_id
,
909 unsigned long count
) {
911 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
912 IndexedDBCursor
* idb_cursor
=
913 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
919 new IndexedDBCallbacks(
920 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
923 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
926 int32 ipc_callbacks_id
,
927 const IndexedDBKey
& key
,
928 const IndexedDBKey
& primary_key
) {
930 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
931 IndexedDBCursor
* idb_cursor
=
932 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
936 idb_cursor
->Continue(
937 key
.IsValid() ? make_scoped_ptr(new IndexedDBKey(key
))
938 : scoped_ptr
<IndexedDBKey
>(),
939 primary_key
.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key
))
940 : scoped_ptr
<IndexedDBKey
>(),
941 new IndexedDBCallbacks(
942 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
945 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
948 int32 ipc_callbacks_id
,
951 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
952 IndexedDBCursor
* idb_cursor
=
953 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
957 idb_cursor
->PrefetchContinue(
959 new IndexedDBCallbacks(
960 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
963 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
966 int unused_prefetches
) {
968 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
969 IndexedDBCursor
* idb_cursor
=
970 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
975 idb_cursor
->PrefetchReset(used_prefetches
, unused_prefetches
);
976 // TODO(cmumford): Handle this error (crbug.com/363397)
978 DLOG(ERROR
) << "Unable to reset prefetch";
981 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
982 int32 ipc_object_id
) {
984 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
985 parent_
->DestroyObject(&map_
, ipc_object_id
);
988 } // namespace content