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/guid.h"
11 #include "base/memory/scoped_vector.h"
12 #include "base/process/process.h"
13 #include "base/stl_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/indexed_db/indexed_db_callbacks.h"
17 #include "content/browser/indexed_db/indexed_db_connection.h"
18 #include "content/browser/indexed_db/indexed_db_context_impl.h"
19 #include "content/browser/indexed_db/indexed_db_cursor.h"
20 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
21 #include "content/browser/indexed_db/indexed_db_metadata.h"
22 #include "content/browser/indexed_db/indexed_db_pending_connection.h"
23 #include "content/browser/indexed_db/indexed_db_value.h"
24 #include "content/browser/renderer_host/render_message_filter.h"
25 #include "content/common/indexed_db/indexed_db_messages.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/user_metrics.h"
28 #include "content/public/common/content_switches.h"
29 #include "content/public/common/result_codes.h"
30 #include "storage/browser/blob/blob_storage_context.h"
31 #include "storage/browser/database/database_util.h"
32 #include "storage/common/database/database_identifier.h"
33 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
36 using storage::DatabaseUtil
;
37 using blink::WebIDBKey
;
41 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
43 net::URLRequestContextGetter
* request_context_getter
,
44 IndexedDBContextImpl
* indexed_db_context
,
45 ChromeBlobStorageContext
* blob_storage_context
)
46 : BrowserMessageFilter(IndexedDBMsgStart
),
47 request_context_getter_(request_context_getter
),
48 request_context_(NULL
),
49 indexed_db_context_(indexed_db_context
),
50 blob_storage_context_(blob_storage_context
),
51 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
52 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
53 ipc_process_id_(ipc_process_id
) {
54 DCHECK(indexed_db_context_
.get());
57 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
59 net::URLRequestContext
* request_context
,
60 IndexedDBContextImpl
* indexed_db_context
,
61 ChromeBlobStorageContext
* blob_storage_context
)
62 : BrowserMessageFilter(IndexedDBMsgStart
),
63 request_context_(request_context
),
64 indexed_db_context_(indexed_db_context
),
65 blob_storage_context_(blob_storage_context
),
66 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
67 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
68 ipc_process_id_(ipc_process_id
) {
69 DCHECK(indexed_db_context_
.get());
72 IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
73 for (auto& iter
: blob_data_handle_map_
)
74 delete iter
.second
.first
;
77 void IndexedDBDispatcherHost::OnChannelConnected(int32 peer_pid
) {
78 BrowserMessageFilter::OnChannelConnected(peer_pid
);
80 if (request_context_getter_
.get()) {
81 DCHECK(!request_context_
);
82 request_context_
= request_context_getter_
->GetURLRequestContext();
83 request_context_getter_
= NULL
;
84 DCHECK(request_context_
);
88 void IndexedDBDispatcherHost::OnChannelClosing() {
89 bool success
= indexed_db_context_
->TaskRunner()->PostTask(
91 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts
, this));
94 ResetDispatcherHosts();
97 void IndexedDBDispatcherHost::OnDestruct() const {
98 // The last reference to the dispatcher may be a posted task, which would
99 // be destructed on the IndexedDB thread. Without this override, that would
100 // take the dispatcher with it. Since the dispatcher may be keeping the
101 // IndexedDBContext alive, it might be destructed to on its own thread,
102 // which is not supported. Ensure destruction runs on the IO thread instead.
103 BrowserThread::DeleteOnIOThread::Destruct(this);
106 void IndexedDBDispatcherHost::ResetDispatcherHosts() {
107 // It is important that the various *_dispatcher_host_ members are reset
108 // on the IndexedDB thread, since there might be incoming messages on that
109 // thread, and we must not reset the dispatcher hosts until after those
110 // messages are processed.
111 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
113 // Note that we explicitly separate CloseAll() from destruction of the
114 // DatabaseDispatcherHost, since CloseAll() can invoke callbacks which need to
115 // be dispatched through database_dispatcher_host_.
116 database_dispatcher_host_
->CloseAll();
117 database_dispatcher_host_
.reset();
118 cursor_dispatcher_host_
.reset();
121 base::TaskRunner
* IndexedDBDispatcherHost::OverrideTaskRunnerForMessage(
122 const IPC::Message
& message
) {
123 if (IPC_MESSAGE_CLASS(message
) != IndexedDBMsgStart
)
126 switch (message
.type()) {
127 case IndexedDBHostMsg_DatabasePut::ID
:
128 case IndexedDBHostMsg_AckReceivedBlobs::ID
:
131 return indexed_db_context_
->TaskRunner();
135 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message
& message
) {
136 if (IPC_MESSAGE_CLASS(message
) != IndexedDBMsgStart
)
139 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread() ||
140 (message
.type() == IndexedDBHostMsg_DatabasePut::ID
||
141 message
.type() == IndexedDBHostMsg_AckReceivedBlobs::ID
));
143 bool handled
= database_dispatcher_host_
->OnMessageReceived(message
) ||
144 cursor_dispatcher_host_
->OnMessageReceived(message
);
148 IPC_BEGIN_MESSAGE_MAP(IndexedDBDispatcherHost
, message
)
149 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames
,
150 OnIDBFactoryGetDatabaseNames
)
151 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen
, OnIDBFactoryOpen
)
152 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase
,
153 OnIDBFactoryDeleteDatabase
)
154 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_AckReceivedBlobs
, OnAckReceivedBlobs
)
155 IPC_MESSAGE_UNHANDLED(handled
= false)
156 IPC_END_MESSAGE_MAP()
161 int32
IndexedDBDispatcherHost::Add(IndexedDBCursor
* cursor
) {
162 if (!cursor_dispatcher_host_
) {
165 return cursor_dispatcher_host_
->map_
.Add(cursor
);
168 int32
IndexedDBDispatcherHost::Add(IndexedDBConnection
* connection
,
170 const GURL
& origin_url
) {
171 if (!database_dispatcher_host_
) {
176 int32 ipc_database_id
= database_dispatcher_host_
->map_
.Add(connection
);
177 Context()->ConnectionOpened(origin_url
, connection
);
178 database_dispatcher_host_
->database_url_map_
[ipc_database_id
] = origin_url
;
179 return ipc_database_id
;
182 void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id
,
184 if (!database_dispatcher_host_
)
186 database_dispatcher_host_
->transaction_url_map_
[host_transaction_id
] = url
;
189 int64
IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id
) {
190 // Inject the renderer process id into the transaction id, to
191 // uniquely identify this transaction, and effectively bind it to
192 // the renderer that initiated it. The lower 32 bits of
193 // transaction_id are guaranteed to be unique within that renderer.
194 base::ProcessId pid
= peer_pid();
195 DCHECK(!(transaction_id
>> 32)) << "Transaction ids can only be 32 bits";
196 static_assert(sizeof(base::ProcessId
) <= sizeof(int32
),
197 "Process ID must fit in 32 bits");
199 return transaction_id
| (static_cast<uint64
>(pid
) << 32);
202 int64
IndexedDBDispatcherHost::RendererTransactionId(
203 int64 host_transaction_id
) {
204 DCHECK(host_transaction_id
>> 32 == peer_pid())
205 << "Invalid renderer target for transaction id";
206 return host_transaction_id
& 0xffffffff;
210 uint32
IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
211 int64 host_transaction_id
) {
212 return host_transaction_id
& 0xffffffff;
216 uint32
IndexedDBDispatcherHost::TransactionIdToProcessId(
217 int64 host_transaction_id
) {
218 return (host_transaction_id
>> 32) & 0xffffffff;
221 std::string
IndexedDBDispatcherHost::HoldBlobData(
222 const IndexedDBBlobInfo
& blob_info
) {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
224 std::string uuid
= blob_info
.uuid();
225 storage::BlobStorageContext
* context
= blob_storage_context_
->context();
226 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
228 uuid
= base::GenerateGUID();
229 scoped_refptr
<storage::BlobData
> blob_data
= new storage::BlobData(uuid
);
230 blob_data
->set_content_type(base::UTF16ToUTF8(blob_info
.type()));
231 blob_data
->AppendFile(blob_info
.file_path(), 0, blob_info
.size(),
232 blob_info
.last_modified());
233 blob_data_handle
= context
->AddFinishedBlob(blob_data
.get());
235 auto iter
= blob_data_handle_map_
.find(uuid
);
236 if (iter
!= blob_data_handle_map_
.end()) {
237 iter
->second
.second
+= 1;
240 blob_data_handle
= context
->GetBlobDataFromUUID(uuid
);
243 DCHECK(!ContainsKey(blob_data_handle_map_
, uuid
));
244 blob_data_handle_map_
[uuid
] = std::make_pair(blob_data_handle
.release(), 1);
248 void IndexedDBDispatcherHost::DropBlobData(const std::string
& uuid
) {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
250 BlobDataHandleMap::iterator iter
= blob_data_handle_map_
.find(uuid
);
251 if (iter
!= blob_data_handle_map_
.end()) {
252 DCHECK_GE(iter
->second
.second
, 1);
253 if (iter
->second
.second
== 1) {
254 delete iter
->second
.first
;
255 blob_data_handle_map_
.erase(iter
);
257 iter
->second
.second
-= 1;
260 DLOG(FATAL
) << "Failed to find blob UUID in map:" << uuid
;
264 IndexedDBCursor
* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id
) {
265 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
266 return cursor_dispatcher_host_
->map_
.Lookup(ipc_cursor_id
);
269 ::IndexedDBDatabaseMetadata
IndexedDBDispatcherHost::ConvertMetadata(
270 const content::IndexedDBDatabaseMetadata
& web_metadata
) {
271 ::IndexedDBDatabaseMetadata metadata
;
272 metadata
.id
= web_metadata
.id
;
273 metadata
.name
= web_metadata
.name
;
274 metadata
.version
= web_metadata
.version
;
275 metadata
.int_version
= web_metadata
.int_version
;
276 metadata
.max_object_store_id
= web_metadata
.max_object_store_id
;
278 for (const auto& iter
: web_metadata
.object_stores
) {
279 const content::IndexedDBObjectStoreMetadata
& web_store_metadata
=
281 ::IndexedDBObjectStoreMetadata idb_store_metadata
;
282 idb_store_metadata
.id
= web_store_metadata
.id
;
283 idb_store_metadata
.name
= web_store_metadata
.name
;
284 idb_store_metadata
.keyPath
= web_store_metadata
.key_path
;
285 idb_store_metadata
.autoIncrement
= web_store_metadata
.auto_increment
;
286 idb_store_metadata
.max_index_id
= web_store_metadata
.max_index_id
;
288 for (const auto& index_iter
: web_store_metadata
.indexes
) {
289 const content::IndexedDBIndexMetadata
& web_index_metadata
=
291 ::IndexedDBIndexMetadata idb_index_metadata
;
292 idb_index_metadata
.id
= web_index_metadata
.id
;
293 idb_index_metadata
.name
= web_index_metadata
.name
;
294 idb_index_metadata
.keyPath
= web_index_metadata
.key_path
;
295 idb_index_metadata
.unique
= web_index_metadata
.unique
;
296 idb_index_metadata
.multiEntry
= web_index_metadata
.multi_entry
;
297 idb_store_metadata
.indexes
.push_back(idb_index_metadata
);
299 metadata
.object_stores
.push_back(idb_store_metadata
);
304 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
305 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params
& params
) {
306 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
307 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
310 storage::GetOriginFromIdentifier(params
.database_identifier
);
312 Context()->GetIDBFactory()->GetDatabaseNames(
313 new IndexedDBCallbacks(
314 this, params
.ipc_thread_id
, params
.ipc_callbacks_id
),
320 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
321 const IndexedDBHostMsg_FactoryOpen_Params
& params
) {
322 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
323 base::TimeTicks begin_time
= base::TimeTicks::Now();
324 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
327 storage::GetOriginFromIdentifier(params
.database_identifier
);
329 int64 host_transaction_id
= HostTransactionId(params
.transaction_id
);
331 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
332 // created) if this origin is already over quota.
333 scoped_refptr
<IndexedDBCallbacks
> callbacks
=
334 new IndexedDBCallbacks(this,
335 params
.ipc_thread_id
,
336 params
.ipc_callbacks_id
,
337 params
.ipc_database_callbacks_id
,
340 callbacks
->SetConnectionOpenStartTime(begin_time
);
341 scoped_refptr
<IndexedDBDatabaseCallbacks
> database_callbacks
=
342 new IndexedDBDatabaseCallbacks(
343 this, params
.ipc_thread_id
, params
.ipc_database_callbacks_id
);
344 IndexedDBPendingConnection
connection(callbacks
,
349 DCHECK(request_context_
);
350 Context()->GetIDBFactory()->Open(
351 params
.name
, connection
, request_context_
, origin_url
, indexed_db_path
);
354 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
355 const IndexedDBHostMsg_FactoryDeleteDatabase_Params
& params
) {
356 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
358 storage::GetOriginFromIdentifier(params
.database_identifier
);
359 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
360 DCHECK(request_context_
);
361 Context()->GetIDBFactory()->DeleteDatabase(
364 new IndexedDBCallbacks(
365 this, params
.ipc_thread_id
, params
.ipc_callbacks_id
),
370 // OnPutHelper exists only to allow us to hop threads while holding a reference
371 // to the IndexedDBDispatcherHost.
372 void IndexedDBDispatcherHost::OnPutHelper(
373 const IndexedDBHostMsg_DatabasePut_Params
& params
,
374 std::vector
<storage::BlobDataHandle
*> handles
) {
375 database_dispatcher_host_
->OnPut(params
, handles
);
378 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
379 const std::vector
<std::string
>& uuids
) {
380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
381 for (const auto& uuid
: uuids
)
385 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id
,
387 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
388 if (!database_dispatcher_host_
)
390 TransactionIDToURLMap
& transaction_url_map
=
391 database_dispatcher_host_
->transaction_url_map_
;
392 TransactionIDToSizeMap
& transaction_size_map
=
393 database_dispatcher_host_
->transaction_size_map_
;
394 TransactionIDToDatabaseIDMap
& transaction_database_map
=
395 database_dispatcher_host_
->transaction_database_map_
;
397 Context()->TransactionComplete(transaction_url_map
[host_transaction_id
]);
398 transaction_url_map
.erase(host_transaction_id
);
399 transaction_size_map
.erase(host_transaction_id
);
400 transaction_database_map
.erase(host_transaction_id
);
403 //////////////////////////////////////////////////////////////////////
407 template <typename ObjectType
>
408 ObjectType
* IndexedDBDispatcherHost::GetOrTerminateProcess(
409 IDMap
<ObjectType
, IDMapOwnPointer
>* map
,
410 int32 ipc_return_object_id
) {
411 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
412 ObjectType
* return_object
= map
->Lookup(ipc_return_object_id
);
413 if (!return_object
) {
414 NOTREACHED() << "Uh oh, couldn't find object with id "
415 << ipc_return_object_id
;
416 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
417 BadMessageReceived();
419 return return_object
;
422 template <typename ObjectType
>
423 ObjectType
* IndexedDBDispatcherHost::GetOrTerminateProcess(
424 RefIDMap
<ObjectType
>* map
,
425 int32 ipc_return_object_id
) {
426 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
427 ObjectType
* return_object
= map
->Lookup(ipc_return_object_id
);
428 if (!return_object
) {
429 NOTREACHED() << "Uh oh, couldn't find object with id "
430 << ipc_return_object_id
;
431 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
432 BadMessageReceived();
434 return return_object
;
437 template <typename MapType
>
438 void IndexedDBDispatcherHost::DestroyObject(MapType
* map
, int32 ipc_object_id
) {
439 GetOrTerminateProcess(map
, ipc_object_id
);
440 map
->Remove(ipc_object_id
);
443 //////////////////////////////////////////////////////////////////////
444 // IndexedDBDispatcherHost::DatabaseDispatcherHost
447 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
448 IndexedDBDispatcherHost
* parent
)
450 map_
.set_check_on_null_data(true);
453 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
454 // TODO(alecflett): uncomment these when we find the source of these leaks.
455 // DCHECK(transaction_size_map_.empty());
456 // DCHECK(transaction_url_map_.empty());
459 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
461 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
462 // Abort outstanding transactions started by connections in the associated
463 // front-end to unblock later transactions. This should only occur on unclean
464 // (crash) or abrupt (process-kill) shutdowns.
465 for (TransactionIDToDatabaseIDMap::iterator iter
=
466 transaction_database_map_
.begin();
467 iter
!= transaction_database_map_
.end();) {
468 int64 transaction_id
= iter
->first
;
469 int32 ipc_database_id
= iter
->second
;
471 IndexedDBConnection
* connection
= map_
.Lookup(ipc_database_id
);
472 if (connection
&& connection
->IsConnected()) {
473 connection
->database()->Abort(
475 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError
));
478 DCHECK(transaction_database_map_
.empty());
480 for (const auto& iter
: database_url_map_
) {
481 IndexedDBConnection
* connection
= map_
.Lookup(iter
.first
);
482 if (connection
&& connection
->IsConnected()) {
484 parent_
->Context()->ConnectionClosed(iter
.second
, connection
);
489 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
490 const IPC::Message
& message
) {
492 (message
.type() == IndexedDBHostMsg_DatabasePut::ID
||
493 message
.type() == IndexedDBHostMsg_AckReceivedBlobs::ID
) ||
494 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
497 IPC_BEGIN_MESSAGE_MAP(
498 IndexedDBDispatcherHost::DatabaseDispatcherHost
, message
)
499 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore
,
501 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore
,
503 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction
,
505 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose
, OnClose
)
506 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored
,
507 OnVersionChangeIgnored
)
508 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed
, OnDestroyed
)
509 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet
, OnGet
)
510 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut
, OnPutWrapper
)
511 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys
, OnSetIndexKeys
)
512 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady
,
514 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor
, OnOpenCursor
)
515 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount
, OnCount
)
516 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange
, OnDeleteRange
)
517 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear
, OnClear
)
518 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex
, OnCreateIndex
)
519 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex
, OnDeleteIndex
)
520 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort
, OnAbort
)
521 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit
, OnCommit
)
522 IPC_MESSAGE_UNHANDLED(handled
= false)
523 IPC_END_MESSAGE_MAP()
528 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
529 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params
& params
) {
531 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
532 IndexedDBConnection
* connection
=
533 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
534 if (!connection
|| !connection
->IsConnected())
537 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
538 connection
->database()->CreateObjectStore(host_transaction_id
,
539 params
.object_store_id
,
542 params
.auto_increment
);
543 if (parent_
->Context()->IsOverQuota(
544 database_url_map_
[params
.ipc_database_id
])) {
545 connection
->database()->Abort(
547 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
551 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
552 int32 ipc_database_id
,
553 int64 transaction_id
,
554 int64 object_store_id
) {
556 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
557 IndexedDBConnection
* connection
=
558 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
559 if (!connection
|| !connection
->IsConnected())
562 connection
->database()->DeleteObjectStore(
563 parent_
->HostTransactionId(transaction_id
), object_store_id
);
566 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
567 const IndexedDBHostMsg_DatabaseCreateTransaction_Params
& params
) {
569 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
570 IndexedDBConnection
* connection
=
571 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
572 if (!connection
|| !connection
->IsConnected())
575 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
577 if (transaction_database_map_
.find(host_transaction_id
) !=
578 transaction_database_map_
.end()) {
579 DLOG(ERROR
) << "Duplicate host_transaction_id.";
583 connection
->database()->CreateTransaction(
584 host_transaction_id
, connection
, params
.object_store_ids
, params
.mode
);
585 transaction_database_map_
[host_transaction_id
] = params
.ipc_database_id
;
586 parent_
->RegisterTransactionId(host_transaction_id
,
587 database_url_map_
[params
.ipc_database_id
]);
590 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
591 int32 ipc_database_id
) {
593 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
594 IndexedDBConnection
* connection
=
595 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
596 if (!connection
|| !connection
->IsConnected())
601 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
602 int32 ipc_database_id
) {
604 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
605 IndexedDBConnection
* connection
=
606 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
607 if (!connection
|| !connection
->IsConnected())
609 connection
->VersionChangeIgnored();
612 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
613 int32 ipc_object_id
) {
615 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
616 IndexedDBConnection
* connection
= map_
.Lookup(ipc_object_id
);
617 if (connection
->IsConnected())
620 ->ConnectionClosed(database_url_map_
[ipc_object_id
], connection
);
621 database_url_map_
.erase(ipc_object_id
);
622 parent_
->DestroyObject(&map_
, ipc_object_id
);
625 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
626 const IndexedDBHostMsg_DatabaseGet_Params
& params
) {
628 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
629 IndexedDBConnection
* connection
=
630 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
631 if (!connection
|| !connection
->IsConnected())
634 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
635 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
636 connection
->database()->Get(
637 parent_
->HostTransactionId(params
.transaction_id
),
638 params
.object_store_id
,
640 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
645 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
646 const IndexedDBHostMsg_DatabasePut_Params
& params
) {
647 std::vector
<storage::BlobDataHandle
*> handles
;
648 for (size_t i
= 0; i
< params
.blob_or_file_info
.size(); ++i
) {
649 const IndexedDBMsg_BlobOrFileInfo
& info
= params
.blob_or_file_info
[i
];
650 handles
.push_back(parent_
->blob_storage_context_
->context()
651 ->GetBlobDataFromUUID(info
.uuid
)
654 parent_
->indexed_db_context_
->TaskRunner()->PostTask(
657 &IndexedDBDispatcherHost::OnPutHelper
, parent_
, params
, handles
));
660 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
661 const IndexedDBHostMsg_DatabasePut_Params
& params
,
662 std::vector
<storage::BlobDataHandle
*> handles
) {
664 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
666 ScopedVector
<storage::BlobDataHandle
> scoped_handles
;
667 scoped_handles
.swap(handles
);
669 IndexedDBConnection
* connection
=
670 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
671 if (!connection
|| !connection
->IsConnected())
673 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
674 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
676 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
678 std::vector
<IndexedDBBlobInfo
> blob_info(params
.blob_or_file_info
.size());
680 ChildProcessSecurityPolicyImpl
* policy
=
681 ChildProcessSecurityPolicyImpl::GetInstance();
683 for (size_t i
= 0; i
< params
.blob_or_file_info
.size(); ++i
) {
684 const IndexedDBMsg_BlobOrFileInfo
& info
= params
.blob_or_file_info
[i
];
687 if (!info
.file_path
.empty()) {
688 path
= base::FilePath::FromUTF16Unsafe(info
.file_path
);
689 if (!policy
->CanReadFile(parent_
->ipc_process_id_
, path
)) {
690 parent_
->BadMessageReceived();
695 IndexedDBBlobInfo(info
.uuid
, path
, info
.file_name
, info
.mime_type
);
696 if (info
.size
!= static_cast<uint64_t>(-1)) {
697 blob_info
[i
].set_last_modified(
698 base::Time::FromDoubleT(info
.last_modified
));
699 blob_info
[i
].set_size(info
.size
);
702 blob_info
[i
] = IndexedDBBlobInfo(info
.uuid
, info
.mime_type
, info
.size
);
706 // TODO(alecflett): Avoid a copy here.
707 IndexedDBValue value
;
708 value
.bits
= params
.value
;
709 value
.blob_info
.swap(blob_info
);
710 connection
->database()->Put(host_transaction_id
,
711 params
.object_store_id
,
714 make_scoped_ptr(new IndexedDBKey(params
.key
)),
718 TransactionIDToSizeMap
* map
=
719 &parent_
->database_dispatcher_host_
->transaction_size_map_
;
720 // Size can't be big enough to overflow because it represents the
721 // actual bytes passed through IPC.
722 (*map
)[host_transaction_id
] += params
.value
.size();
725 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
726 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params
& params
) {
728 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
729 IndexedDBConnection
* connection
=
730 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
731 if (!connection
|| !connection
->IsConnected())
734 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
735 connection
->database()->SetIndexKeys(
737 params
.object_store_id
,
738 make_scoped_ptr(new IndexedDBKey(params
.primary_key
)),
742 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
743 int32 ipc_database_id
,
744 int64 transaction_id
,
745 int64 object_store_id
,
746 const std::vector
<int64
>& index_ids
) {
748 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
749 IndexedDBConnection
* connection
=
750 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
751 if (!connection
|| !connection
->IsConnected())
754 connection
->database()->SetIndexesReady(
755 parent_
->HostTransactionId(transaction_id
), object_store_id
, index_ids
);
758 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
759 const IndexedDBHostMsg_DatabaseOpenCursor_Params
& params
) {
761 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
762 IndexedDBConnection
* connection
=
763 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
764 if (!connection
|| !connection
->IsConnected())
767 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
768 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
, -1));
769 connection
->database()->OpenCursor(
770 parent_
->HostTransactionId(params
.transaction_id
),
771 params
.object_store_id
,
773 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
780 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
781 const IndexedDBHostMsg_DatabaseCount_Params
& params
) {
783 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
784 IndexedDBConnection
* connection
=
785 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
786 if (!connection
|| !connection
->IsConnected())
789 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
790 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
791 connection
->database()->Count(
792 parent_
->HostTransactionId(params
.transaction_id
),
793 params
.object_store_id
,
795 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
799 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
800 const IndexedDBHostMsg_DatabaseDeleteRange_Params
& params
) {
802 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
803 IndexedDBConnection
* connection
=
804 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
805 if (!connection
|| !connection
->IsConnected())
808 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
809 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
810 connection
->database()->DeleteRange(
811 parent_
->HostTransactionId(params
.transaction_id
),
812 params
.object_store_id
,
813 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
817 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
819 int32 ipc_callbacks_id
,
820 int32 ipc_database_id
,
821 int64 transaction_id
,
822 int64 object_store_id
) {
824 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
825 IndexedDBConnection
* connection
=
826 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
827 if (!connection
|| !connection
->IsConnected())
830 scoped_refptr
<IndexedDBCallbacks
> callbacks(
831 new IndexedDBCallbacks(parent_
, ipc_thread_id
, ipc_callbacks_id
));
833 connection
->database()->Clear(
834 parent_
->HostTransactionId(transaction_id
), object_store_id
, callbacks
);
837 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
838 int32 ipc_database_id
,
839 int64 transaction_id
) {
841 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
842 IndexedDBConnection
* connection
=
843 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
844 if (!connection
|| !connection
->IsConnected())
847 connection
->database()->Abort(parent_
->HostTransactionId(transaction_id
));
850 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
851 int32 ipc_database_id
,
852 int64 transaction_id
) {
854 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
855 IndexedDBConnection
* connection
=
856 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
857 if (!connection
|| !connection
->IsConnected())
860 int64 host_transaction_id
= parent_
->HostTransactionId(transaction_id
);
861 int64 transaction_size
= transaction_size_map_
[host_transaction_id
];
862 if (transaction_size
&&
863 parent_
->Context()->WouldBeOverQuota(
864 transaction_url_map_
[host_transaction_id
], transaction_size
)) {
865 connection
->database()->Abort(
867 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
871 connection
->database()->Commit(host_transaction_id
);
874 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
875 const IndexedDBHostMsg_DatabaseCreateIndex_Params
& params
) {
877 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
878 IndexedDBConnection
* connection
=
879 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
880 if (!connection
|| !connection
->IsConnected())
883 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
884 connection
->database()->CreateIndex(host_transaction_id
,
885 params
.object_store_id
,
891 if (parent_
->Context()->IsOverQuota(
892 database_url_map_
[params
.ipc_database_id
])) {
893 connection
->database()->Abort(
895 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
899 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
900 int32 ipc_database_id
,
901 int64 transaction_id
,
902 int64 object_store_id
,
905 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
906 IndexedDBConnection
* connection
=
907 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
908 if (!connection
|| !connection
->IsConnected())
911 connection
->database()->DeleteIndex(
912 parent_
->HostTransactionId(transaction_id
), object_store_id
, index_id
);
915 //////////////////////////////////////////////////////////////////////
916 // IndexedDBDispatcherHost::CursorDispatcherHost
919 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
920 IndexedDBDispatcherHost
* parent
)
922 map_
.set_check_on_null_data(true);
925 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
927 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
928 const IPC::Message
& message
) {
930 IPC_BEGIN_MESSAGE_MAP(
931 IndexedDBDispatcherHost::CursorDispatcherHost
, message
)
932 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance
, OnAdvance
)
933 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue
, OnContinue
)
934 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch
, OnPrefetch
)
935 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset
, OnPrefetchReset
)
936 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed
, OnDestroyed
)
937 IPC_MESSAGE_UNHANDLED(handled
= false)
938 IPC_END_MESSAGE_MAP()
942 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
947 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
950 int32 ipc_callbacks_id
,
953 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
954 IndexedDBCursor
* idb_cursor
=
955 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
961 new IndexedDBCallbacks(
962 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
965 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
968 int32 ipc_callbacks_id
,
969 const IndexedDBKey
& key
,
970 const IndexedDBKey
& primary_key
) {
972 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
973 IndexedDBCursor
* idb_cursor
=
974 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
978 idb_cursor
->Continue(
979 key
.IsValid() ? make_scoped_ptr(new IndexedDBKey(key
))
980 : scoped_ptr
<IndexedDBKey
>(),
981 primary_key
.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key
))
982 : scoped_ptr
<IndexedDBKey
>(),
983 new IndexedDBCallbacks(
984 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
987 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
990 int32 ipc_callbacks_id
,
993 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
994 IndexedDBCursor
* idb_cursor
=
995 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
999 idb_cursor
->PrefetchContinue(
1001 new IndexedDBCallbacks(
1002 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
1005 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
1006 int32 ipc_cursor_id
,
1007 int used_prefetches
,
1008 int unused_prefetches
) {
1010 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
1011 IndexedDBCursor
* idb_cursor
=
1012 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
1017 idb_cursor
->PrefetchReset(used_prefetches
, unused_prefetches
);
1018 // TODO(cmumford): Handle this error (crbug.com/363397)
1020 DLOG(ERROR
) << "Unable to reset prefetch";
1023 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
1024 int32 ipc_object_id
) {
1026 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
1027 parent_
->DestroyObject(&map_
, ipc_object_id
);
1030 } // namespace content