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 "storage/browser/blob/blob_storage_context.h"
30 #include "storage/browser/database/database_util.h"
31 #include "storage/common/database/database_identifier.h"
32 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
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 (const auto& iter
: web_metadata
.object_stores
) {
244 const content::IndexedDBObjectStoreMetadata
& web_store_metadata
=
246 ::IndexedDBObjectStoreMetadata idb_store_metadata
;
247 idb_store_metadata
.id
= web_store_metadata
.id
;
248 idb_store_metadata
.name
= web_store_metadata
.name
;
249 idb_store_metadata
.keyPath
= web_store_metadata
.key_path
;
250 idb_store_metadata
.autoIncrement
= web_store_metadata
.auto_increment
;
251 idb_store_metadata
.max_index_id
= web_store_metadata
.max_index_id
;
253 for (const auto& index_iter
: web_store_metadata
.indexes
) {
254 const content::IndexedDBIndexMetadata
& web_index_metadata
=
256 ::IndexedDBIndexMetadata idb_index_metadata
;
257 idb_index_metadata
.id
= web_index_metadata
.id
;
258 idb_index_metadata
.name
= web_index_metadata
.name
;
259 idb_index_metadata
.keyPath
= web_index_metadata
.key_path
;
260 idb_index_metadata
.unique
= web_index_metadata
.unique
;
261 idb_index_metadata
.multiEntry
= web_index_metadata
.multi_entry
;
262 idb_store_metadata
.indexes
.push_back(idb_index_metadata
);
264 metadata
.object_stores
.push_back(idb_store_metadata
);
269 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
270 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params
& params
) {
271 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
272 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
275 storage::GetOriginFromIdentifier(params
.database_identifier
);
277 Context()->GetIDBFactory()->GetDatabaseNames(
278 new IndexedDBCallbacks(
279 this, params
.ipc_thread_id
, params
.ipc_callbacks_id
),
285 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
286 const IndexedDBHostMsg_FactoryOpen_Params
& params
) {
287 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
288 base::TimeTicks begin_time
= base::TimeTicks::Now();
289 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
292 storage::GetOriginFromIdentifier(params
.database_identifier
);
294 int64 host_transaction_id
= HostTransactionId(params
.transaction_id
);
296 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
297 // created) if this origin is already over quota.
298 scoped_refptr
<IndexedDBCallbacks
> callbacks
=
299 new IndexedDBCallbacks(this,
300 params
.ipc_thread_id
,
301 params
.ipc_callbacks_id
,
302 params
.ipc_database_callbacks_id
,
305 callbacks
->SetConnectionOpenStartTime(begin_time
);
306 scoped_refptr
<IndexedDBDatabaseCallbacks
> database_callbacks
=
307 new IndexedDBDatabaseCallbacks(
308 this, params
.ipc_thread_id
, params
.ipc_database_callbacks_id
);
309 IndexedDBPendingConnection
connection(callbacks
,
314 DCHECK(request_context_
);
315 Context()->GetIDBFactory()->Open(
316 params
.name
, connection
, request_context_
, origin_url
, indexed_db_path
);
319 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
320 const IndexedDBHostMsg_FactoryDeleteDatabase_Params
& params
) {
321 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
323 storage::GetOriginFromIdentifier(params
.database_identifier
);
324 base::FilePath indexed_db_path
= indexed_db_context_
->data_path();
325 DCHECK(request_context_
);
326 Context()->GetIDBFactory()->DeleteDatabase(
329 new IndexedDBCallbacks(
330 this, params
.ipc_thread_id
, params
.ipc_callbacks_id
),
335 // OnPutHelper exists only to allow us to hop threads while holding a reference
336 // to the IndexedDBDispatcherHost.
337 void IndexedDBDispatcherHost::OnPutHelper(
338 const IndexedDBHostMsg_DatabasePut_Params
& params
,
339 std::vector
<storage::BlobDataHandle
*> handles
) {
340 database_dispatcher_host_
->OnPut(params
, handles
);
343 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
344 const std::vector
<std::string
>& uuids
) {
345 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
346 for (const auto& uuid
: uuids
)
347 DropBlobDataHandle(uuid
);
350 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id
,
352 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
353 if (!database_dispatcher_host_
)
355 TransactionIDToURLMap
& transaction_url_map
=
356 database_dispatcher_host_
->transaction_url_map_
;
357 TransactionIDToSizeMap
& transaction_size_map
=
358 database_dispatcher_host_
->transaction_size_map_
;
359 TransactionIDToDatabaseIDMap
& transaction_database_map
=
360 database_dispatcher_host_
->transaction_database_map_
;
362 Context()->TransactionComplete(transaction_url_map
[host_transaction_id
]);
363 transaction_url_map
.erase(host_transaction_id
);
364 transaction_size_map
.erase(host_transaction_id
);
365 transaction_database_map
.erase(host_transaction_id
);
368 //////////////////////////////////////////////////////////////////////
372 template <typename ObjectType
>
373 ObjectType
* IndexedDBDispatcherHost::GetOrTerminateProcess(
374 IDMap
<ObjectType
, IDMapOwnPointer
>* map
,
375 int32 ipc_return_object_id
) {
376 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
377 ObjectType
* return_object
= map
->Lookup(ipc_return_object_id
);
378 if (!return_object
) {
379 NOTREACHED() << "Uh oh, couldn't find object with id "
380 << ipc_return_object_id
;
381 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
382 BadMessageReceived();
384 return return_object
;
387 template <typename ObjectType
>
388 ObjectType
* IndexedDBDispatcherHost::GetOrTerminateProcess(
389 RefIDMap
<ObjectType
>* map
,
390 int32 ipc_return_object_id
) {
391 DCHECK(indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
392 ObjectType
* return_object
= map
->Lookup(ipc_return_object_id
);
393 if (!return_object
) {
394 NOTREACHED() << "Uh oh, couldn't find object with id "
395 << ipc_return_object_id
;
396 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
397 BadMessageReceived();
399 return return_object
;
402 template <typename MapType
>
403 void IndexedDBDispatcherHost::DestroyObject(MapType
* map
, int32 ipc_object_id
) {
404 GetOrTerminateProcess(map
, ipc_object_id
);
405 map
->Remove(ipc_object_id
);
408 //////////////////////////////////////////////////////////////////////
409 // IndexedDBDispatcherHost::DatabaseDispatcherHost
412 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
413 IndexedDBDispatcherHost
* parent
)
415 map_
.set_check_on_null_data(true);
418 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
419 // TODO(alecflett): uncomment these when we find the source of these leaks.
420 // DCHECK(transaction_size_map_.empty());
421 // DCHECK(transaction_url_map_.empty());
424 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
426 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
427 // Abort outstanding transactions started by connections in the associated
428 // front-end to unblock later transactions. This should only occur on unclean
429 // (crash) or abrupt (process-kill) shutdowns.
430 for (TransactionIDToDatabaseIDMap::iterator iter
=
431 transaction_database_map_
.begin();
432 iter
!= transaction_database_map_
.end();) {
433 int64 transaction_id
= iter
->first
;
434 int32 ipc_database_id
= iter
->second
;
436 IndexedDBConnection
* connection
= map_
.Lookup(ipc_database_id
);
437 if (connection
&& connection
->IsConnected()) {
438 connection
->database()->Abort(
440 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError
));
443 DCHECK(transaction_database_map_
.empty());
445 for (const auto& iter
: database_url_map_
) {
446 IndexedDBConnection
* connection
= map_
.Lookup(iter
.first
);
447 if (connection
&& connection
->IsConnected()) {
449 parent_
->Context()->ConnectionClosed(iter
.second
, connection
);
454 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
455 const IPC::Message
& message
) {
458 (message
.type() == IndexedDBHostMsg_DatabasePut::ID
) ||
459 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
462 IPC_BEGIN_MESSAGE_MAP(
463 IndexedDBDispatcherHost::DatabaseDispatcherHost
, message
)
464 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore
,
466 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore
,
468 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction
,
470 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose
, OnClose
)
471 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored
,
472 OnVersionChangeIgnored
)
473 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed
, OnDestroyed
)
474 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet
, OnGet
)
475 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut
, OnPutWrapper
)
476 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys
, OnSetIndexKeys
)
477 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady
,
479 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor
, OnOpenCursor
)
480 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount
, OnCount
)
481 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange
, OnDeleteRange
)
482 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear
, OnClear
)
483 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex
, OnCreateIndex
)
484 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex
, OnDeleteIndex
)
485 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort
, OnAbort
)
486 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit
, OnCommit
)
487 IPC_MESSAGE_UNHANDLED(handled
= false)
488 IPC_END_MESSAGE_MAP()
493 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
494 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params
& params
) {
496 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
497 IndexedDBConnection
* connection
=
498 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
499 if (!connection
|| !connection
->IsConnected())
502 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
503 connection
->database()->CreateObjectStore(host_transaction_id
,
504 params
.object_store_id
,
507 params
.auto_increment
);
508 if (parent_
->Context()->IsOverQuota(
509 database_url_map_
[params
.ipc_database_id
])) {
510 connection
->database()->Abort(
512 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
516 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
517 int32 ipc_database_id
,
518 int64 transaction_id
,
519 int64 object_store_id
) {
521 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
522 IndexedDBConnection
* connection
=
523 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
524 if (!connection
|| !connection
->IsConnected())
527 connection
->database()->DeleteObjectStore(
528 parent_
->HostTransactionId(transaction_id
), object_store_id
);
531 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
532 const IndexedDBHostMsg_DatabaseCreateTransaction_Params
& params
) {
534 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
535 IndexedDBConnection
* connection
=
536 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
537 if (!connection
|| !connection
->IsConnected())
540 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
542 if (transaction_database_map_
.find(host_transaction_id
) !=
543 transaction_database_map_
.end()) {
544 DLOG(ERROR
) << "Duplicate host_transaction_id.";
548 connection
->database()->CreateTransaction(
549 host_transaction_id
, connection
, params
.object_store_ids
, params
.mode
);
550 transaction_database_map_
[host_transaction_id
] = params
.ipc_database_id
;
551 parent_
->RegisterTransactionId(host_transaction_id
,
552 database_url_map_
[params
.ipc_database_id
]);
555 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
556 int32 ipc_database_id
) {
558 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
559 IndexedDBConnection
* connection
=
560 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
561 if (!connection
|| !connection
->IsConnected())
566 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
567 int32 ipc_database_id
) {
569 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
570 IndexedDBConnection
* connection
=
571 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
572 if (!connection
|| !connection
->IsConnected())
574 connection
->VersionChangeIgnored();
577 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
578 int32 ipc_object_id
) {
580 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
581 IndexedDBConnection
* connection
= map_
.Lookup(ipc_object_id
);
582 if (connection
->IsConnected())
585 ->ConnectionClosed(database_url_map_
[ipc_object_id
], connection
);
586 database_url_map_
.erase(ipc_object_id
);
587 parent_
->DestroyObject(&map_
, ipc_object_id
);
590 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
591 const IndexedDBHostMsg_DatabaseGet_Params
& params
) {
593 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
594 IndexedDBConnection
* connection
=
595 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
596 if (!connection
|| !connection
->IsConnected())
599 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
600 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
601 connection
->database()->Get(
602 parent_
->HostTransactionId(params
.transaction_id
),
603 params
.object_store_id
,
605 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
610 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
611 const IndexedDBHostMsg_DatabasePut_Params
& params
) {
612 std::vector
<storage::BlobDataHandle
*> handles
;
613 for (size_t i
= 0; i
< params
.blob_or_file_info
.size(); ++i
) {
614 const IndexedDBMsg_BlobOrFileInfo
& info
= params
.blob_or_file_info
[i
];
615 handles
.push_back(parent_
->blob_storage_context_
->context()
616 ->GetBlobDataFromUUID(info
.uuid
)
619 parent_
->indexed_db_context_
->TaskRunner()->PostTask(
622 &IndexedDBDispatcherHost::OnPutHelper
, parent_
, params
, handles
));
625 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
626 const IndexedDBHostMsg_DatabasePut_Params
& params
,
627 std::vector
<storage::BlobDataHandle
*> handles
) {
629 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
631 ScopedVector
<storage::BlobDataHandle
> scoped_handles
;
632 scoped_handles
.swap(handles
);
634 IndexedDBConnection
* connection
=
635 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
636 if (!connection
|| !connection
->IsConnected())
638 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
639 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
641 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
643 std::vector
<IndexedDBBlobInfo
> blob_info(params
.blob_or_file_info
.size());
645 ChildProcessSecurityPolicyImpl
* policy
=
646 ChildProcessSecurityPolicyImpl::GetInstance();
648 for (size_t i
= 0; i
< params
.blob_or_file_info
.size(); ++i
) {
649 const IndexedDBMsg_BlobOrFileInfo
& info
= params
.blob_or_file_info
[i
];
651 base::FilePath path
= base::FilePath::FromUTF16Unsafe(info
.file_path
);
652 if (!policy
->CanReadFile(parent_
->ipc_process_id_
, path
)) {
653 parent_
->BadMessageReceived();
657 IndexedDBBlobInfo(info
.uuid
, path
, info
.file_name
, info
.mime_type
);
658 if (info
.size
!= static_cast<uint64_t>(-1)) {
659 blob_info
[i
].set_last_modified(
660 base::Time::FromDoubleT(info
.last_modified
));
661 blob_info
[i
].set_size(info
.size
);
664 blob_info
[i
] = IndexedDBBlobInfo(info
.uuid
, info
.mime_type
, info
.size
);
668 // TODO(alecflett): Avoid a copy here.
669 IndexedDBValue value
;
670 value
.bits
= params
.value
;
671 value
.blob_info
.swap(blob_info
);
672 connection
->database()->Put(host_transaction_id
,
673 params
.object_store_id
,
676 make_scoped_ptr(new IndexedDBKey(params
.key
)),
680 TransactionIDToSizeMap
* map
=
681 &parent_
->database_dispatcher_host_
->transaction_size_map_
;
682 // Size can't be big enough to overflow because it represents the
683 // actual bytes passed through IPC.
684 (*map
)[host_transaction_id
] += params
.value
.size();
687 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
688 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params
& params
) {
690 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
691 IndexedDBConnection
* connection
=
692 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
693 if (!connection
|| !connection
->IsConnected())
696 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
697 connection
->database()->SetIndexKeys(
699 params
.object_store_id
,
700 make_scoped_ptr(new IndexedDBKey(params
.primary_key
)),
704 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
705 int32 ipc_database_id
,
706 int64 transaction_id
,
707 int64 object_store_id
,
708 const std::vector
<int64
>& index_ids
) {
710 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
711 IndexedDBConnection
* connection
=
712 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
713 if (!connection
|| !connection
->IsConnected())
716 connection
->database()->SetIndexesReady(
717 parent_
->HostTransactionId(transaction_id
), object_store_id
, index_ids
);
720 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
721 const IndexedDBHostMsg_DatabaseOpenCursor_Params
& params
) {
723 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
724 IndexedDBConnection
* connection
=
725 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
726 if (!connection
|| !connection
->IsConnected())
729 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
730 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
, -1));
731 connection
->database()->OpenCursor(
732 parent_
->HostTransactionId(params
.transaction_id
),
733 params
.object_store_id
,
735 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
742 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
743 const IndexedDBHostMsg_DatabaseCount_Params
& params
) {
745 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
746 IndexedDBConnection
* connection
=
747 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
748 if (!connection
|| !connection
->IsConnected())
751 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
752 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
753 connection
->database()->Count(
754 parent_
->HostTransactionId(params
.transaction_id
),
755 params
.object_store_id
,
757 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
761 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
762 const IndexedDBHostMsg_DatabaseDeleteRange_Params
& params
) {
764 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
765 IndexedDBConnection
* connection
=
766 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
767 if (!connection
|| !connection
->IsConnected())
770 scoped_refptr
<IndexedDBCallbacks
> callbacks(new IndexedDBCallbacks(
771 parent_
, params
.ipc_thread_id
, params
.ipc_callbacks_id
));
772 connection
->database()->DeleteRange(
773 parent_
->HostTransactionId(params
.transaction_id
),
774 params
.object_store_id
,
775 make_scoped_ptr(new IndexedDBKeyRange(params
.key_range
)),
779 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
781 int32 ipc_callbacks_id
,
782 int32 ipc_database_id
,
783 int64 transaction_id
,
784 int64 object_store_id
) {
786 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
787 IndexedDBConnection
* connection
=
788 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
789 if (!connection
|| !connection
->IsConnected())
792 scoped_refptr
<IndexedDBCallbacks
> callbacks(
793 new IndexedDBCallbacks(parent_
, ipc_thread_id
, ipc_callbacks_id
));
795 connection
->database()->Clear(
796 parent_
->HostTransactionId(transaction_id
), object_store_id
, callbacks
);
799 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
800 int32 ipc_database_id
,
801 int64 transaction_id
) {
803 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
804 IndexedDBConnection
* connection
=
805 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
806 if (!connection
|| !connection
->IsConnected())
809 connection
->database()->Abort(parent_
->HostTransactionId(transaction_id
));
812 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
813 int32 ipc_database_id
,
814 int64 transaction_id
) {
816 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
817 IndexedDBConnection
* connection
=
818 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
819 if (!connection
|| !connection
->IsConnected())
822 int64 host_transaction_id
= parent_
->HostTransactionId(transaction_id
);
823 int64 transaction_size
= transaction_size_map_
[host_transaction_id
];
824 if (transaction_size
&&
825 parent_
->Context()->WouldBeOverQuota(
826 transaction_url_map_
[host_transaction_id
], transaction_size
)) {
827 connection
->database()->Abort(
829 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
833 connection
->database()->Commit(host_transaction_id
);
836 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
837 const IndexedDBHostMsg_DatabaseCreateIndex_Params
& params
) {
839 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
840 IndexedDBConnection
* connection
=
841 parent_
->GetOrTerminateProcess(&map_
, params
.ipc_database_id
);
842 if (!connection
|| !connection
->IsConnected())
845 int64 host_transaction_id
= parent_
->HostTransactionId(params
.transaction_id
);
846 connection
->database()->CreateIndex(host_transaction_id
,
847 params
.object_store_id
,
853 if (parent_
->Context()->IsOverQuota(
854 database_url_map_
[params
.ipc_database_id
])) {
855 connection
->database()->Abort(
857 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError
));
861 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
862 int32 ipc_database_id
,
863 int64 transaction_id
,
864 int64 object_store_id
,
867 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
868 IndexedDBConnection
* connection
=
869 parent_
->GetOrTerminateProcess(&map_
, ipc_database_id
);
870 if (!connection
|| !connection
->IsConnected())
873 connection
->database()->DeleteIndex(
874 parent_
->HostTransactionId(transaction_id
), object_store_id
, index_id
);
877 //////////////////////////////////////////////////////////////////////
878 // IndexedDBDispatcherHost::CursorDispatcherHost
881 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
882 IndexedDBDispatcherHost
* parent
)
884 map_
.set_check_on_null_data(true);
887 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
889 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
890 const IPC::Message
& message
) {
892 IPC_BEGIN_MESSAGE_MAP(
893 IndexedDBDispatcherHost::CursorDispatcherHost
, message
)
894 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance
, OnAdvance
)
895 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue
, OnContinue
)
896 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch
, OnPrefetch
)
897 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset
, OnPrefetchReset
)
898 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed
, OnDestroyed
)
899 IPC_MESSAGE_UNHANDLED(handled
= false)
900 IPC_END_MESSAGE_MAP()
904 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
909 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
912 int32 ipc_callbacks_id
,
915 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
916 IndexedDBCursor
* idb_cursor
=
917 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
923 new IndexedDBCallbacks(
924 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
927 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
930 int32 ipc_callbacks_id
,
931 const IndexedDBKey
& key
,
932 const IndexedDBKey
& primary_key
) {
934 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
935 IndexedDBCursor
* idb_cursor
=
936 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
940 idb_cursor
->Continue(
941 key
.IsValid() ? make_scoped_ptr(new IndexedDBKey(key
))
942 : scoped_ptr
<IndexedDBKey
>(),
943 primary_key
.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key
))
944 : scoped_ptr
<IndexedDBKey
>(),
945 new IndexedDBCallbacks(
946 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
949 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
952 int32 ipc_callbacks_id
,
955 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
956 IndexedDBCursor
* idb_cursor
=
957 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
961 idb_cursor
->PrefetchContinue(
963 new IndexedDBCallbacks(
964 parent_
, ipc_thread_id
, ipc_callbacks_id
, ipc_cursor_id
));
967 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
970 int unused_prefetches
) {
972 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
973 IndexedDBCursor
* idb_cursor
=
974 parent_
->GetOrTerminateProcess(&map_
, ipc_cursor_id
);
979 idb_cursor
->PrefetchReset(used_prefetches
, unused_prefetches
);
980 // TODO(cmumford): Handle this error (crbug.com/363397)
982 DLOG(ERROR
) << "Unable to reset prefetch";
985 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
986 int32 ipc_object_id
) {
988 parent_
->indexed_db_context_
->TaskRunner()->RunsTasksOnCurrentThread());
989 parent_
->DestroyObject(&map_
, ipc_object_id
);
992 } // namespace content