Roll DEPS for PDFium to 19ae17578f99621100a26dac3e2c7c3dbf7c7cd1
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_dispatcher_host.cc
bloba2e55ef93e6bba3a2088b40e210851db722819bf
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/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_data_builder.h"
31 #include "storage/browser/blob/blob_storage_context.h"
32 #include "storage/browser/database/database_util.h"
33 #include "storage/common/database/database_identifier.h"
34 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
35 #include "url/gurl.h"
37 using storage::DatabaseUtil;
38 using blink::WebIDBKey;
40 namespace content {
42 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
43 int ipc_process_id,
44 net::URLRequestContextGetter* request_context_getter,
45 IndexedDBContextImpl* indexed_db_context,
46 ChromeBlobStorageContext* blob_storage_context)
47 : BrowserMessageFilter(IndexedDBMsgStart),
48 request_context_getter_(request_context_getter),
49 request_context_(NULL),
50 indexed_db_context_(indexed_db_context),
51 blob_storage_context_(blob_storage_context),
52 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
53 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
54 ipc_process_id_(ipc_process_id) {
55 DCHECK(indexed_db_context_.get());
58 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
59 int ipc_process_id,
60 net::URLRequestContext* request_context,
61 IndexedDBContextImpl* indexed_db_context,
62 ChromeBlobStorageContext* blob_storage_context)
63 : BrowserMessageFilter(IndexedDBMsgStart),
64 request_context_(request_context),
65 indexed_db_context_(indexed_db_context),
66 blob_storage_context_(blob_storage_context),
67 database_dispatcher_host_(new DatabaseDispatcherHost(this)),
68 cursor_dispatcher_host_(new CursorDispatcherHost(this)),
69 ipc_process_id_(ipc_process_id) {
70 DCHECK(indexed_db_context_.get());
73 IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
74 for (auto& iter : blob_data_handle_map_)
75 delete iter.second.first;
78 void IndexedDBDispatcherHost::OnChannelConnected(int32 peer_pid) {
79 BrowserMessageFilter::OnChannelConnected(peer_pid);
81 if (request_context_getter_.get()) {
82 DCHECK(!request_context_);
83 request_context_ = request_context_getter_->GetURLRequestContext();
84 request_context_getter_ = NULL;
85 DCHECK(request_context_);
89 void IndexedDBDispatcherHost::OnChannelClosing() {
90 bool success = indexed_db_context_->TaskRunner()->PostTask(
91 FROM_HERE,
92 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this));
94 if (!success)
95 ResetDispatcherHosts();
98 void IndexedDBDispatcherHost::OnDestruct() const {
99 // The last reference to the dispatcher may be a posted task, which would
100 // be destructed on the IndexedDB thread. Without this override, that would
101 // take the dispatcher with it. Since the dispatcher may be keeping the
102 // IndexedDBContext alive, it might be destructed to on its own thread,
103 // which is not supported. Ensure destruction runs on the IO thread instead.
104 BrowserThread::DeleteOnIOThread::Destruct(this);
107 void IndexedDBDispatcherHost::ResetDispatcherHosts() {
108 // It is important that the various *_dispatcher_host_ members are reset
109 // on the IndexedDB thread, since there might be incoming messages on that
110 // thread, and we must not reset the dispatcher hosts until after those
111 // messages are processed.
112 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
114 // Note that we explicitly separate CloseAll() from destruction of the
115 // DatabaseDispatcherHost, since CloseAll() can invoke callbacks which need to
116 // be dispatched through database_dispatcher_host_.
117 database_dispatcher_host_->CloseAll();
118 database_dispatcher_host_.reset();
119 cursor_dispatcher_host_.reset();
122 base::TaskRunner* IndexedDBDispatcherHost::OverrideTaskRunnerForMessage(
123 const IPC::Message& message) {
124 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
125 return NULL;
127 switch (message.type()) {
128 case IndexedDBHostMsg_DatabasePut::ID:
129 case IndexedDBHostMsg_AckReceivedBlobs::ID:
130 return NULL;
131 default:
132 return indexed_db_context_->TaskRunner();
136 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
137 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
138 return false;
140 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread() ||
141 (message.type() == IndexedDBHostMsg_DatabasePut::ID ||
142 message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID));
144 bool handled = database_dispatcher_host_->OnMessageReceived(message) ||
145 cursor_dispatcher_host_->OnMessageReceived(message);
147 if (!handled) {
148 handled = true;
149 IPC_BEGIN_MESSAGE_MAP(IndexedDBDispatcherHost, message)
150 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames,
151 OnIDBFactoryGetDatabaseNames)
152 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen)
153 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase,
154 OnIDBFactoryDeleteDatabase)
155 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_AckReceivedBlobs, OnAckReceivedBlobs)
156 IPC_MESSAGE_UNHANDLED(handled = false)
157 IPC_END_MESSAGE_MAP()
159 return handled;
162 int32 IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) {
163 if (!cursor_dispatcher_host_) {
164 return 0;
166 return cursor_dispatcher_host_->map_.Add(cursor);
169 int32 IndexedDBDispatcherHost::Add(IndexedDBConnection* connection,
170 int32 ipc_thread_id,
171 const GURL& origin_url) {
172 if (!database_dispatcher_host_) {
173 connection->Close();
174 delete connection;
175 return -1;
177 int32 ipc_database_id = database_dispatcher_host_->map_.Add(connection);
178 Context()->ConnectionOpened(origin_url, connection);
179 database_dispatcher_host_->database_url_map_[ipc_database_id] = origin_url;
180 return ipc_database_id;
183 void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id,
184 const GURL& url) {
185 if (!database_dispatcher_host_)
186 return;
187 database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url;
190 int64 IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id) {
191 // Inject the renderer process id into the transaction id, to
192 // uniquely identify this transaction, and effectively bind it to
193 // the renderer that initiated it. The lower 32 bits of
194 // transaction_id are guaranteed to be unique within that renderer.
195 base::ProcessId pid = peer_pid();
196 DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits";
197 static_assert(sizeof(base::ProcessId) <= sizeof(int32),
198 "Process ID must fit in 32 bits");
200 return transaction_id | (static_cast<uint64>(pid) << 32);
203 int64 IndexedDBDispatcherHost::RendererTransactionId(
204 int64 host_transaction_id) {
205 DCHECK(host_transaction_id >> 32 == peer_pid())
206 << "Invalid renderer target for transaction id";
207 return host_transaction_id & 0xffffffff;
210 // static
211 uint32 IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
212 int64 host_transaction_id) {
213 return host_transaction_id & 0xffffffff;
216 // static
217 uint32 IndexedDBDispatcherHost::TransactionIdToProcessId(
218 int64 host_transaction_id) {
219 return (host_transaction_id >> 32) & 0xffffffff;
222 std::string IndexedDBDispatcherHost::HoldBlobData(
223 const IndexedDBBlobInfo& blob_info) {
224 DCHECK_CURRENTLY_ON(BrowserThread::IO);
225 std::string uuid = blob_info.uuid();
226 storage::BlobStorageContext* context = blob_storage_context_->context();
227 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
228 if (uuid.empty()) {
229 uuid = base::GenerateGUID();
230 storage::BlobDataBuilder blob_data_builder(uuid);
231 blob_data_builder.set_content_type(base::UTF16ToUTF8(blob_info.type()));
232 blob_data_builder.AppendFile(blob_info.file_path(), 0, blob_info.size(),
233 blob_info.last_modified());
234 blob_data_handle = context->AddFinishedBlob(&blob_data_builder);
235 } else {
236 auto iter = blob_data_handle_map_.find(uuid);
237 if (iter != blob_data_handle_map_.end()) {
238 iter->second.second += 1;
239 return uuid;
241 blob_data_handle = context->GetBlobDataFromUUID(uuid);
244 DCHECK(!ContainsKey(blob_data_handle_map_, uuid));
245 blob_data_handle_map_[uuid] = std::make_pair(blob_data_handle.release(), 1);
246 return uuid;
249 void IndexedDBDispatcherHost::DropBlobData(const std::string& uuid) {
250 DCHECK_CURRENTLY_ON(BrowserThread::IO);
251 BlobDataHandleMap::iterator iter = blob_data_handle_map_.find(uuid);
252 if (iter != blob_data_handle_map_.end()) {
253 DCHECK_GE(iter->second.second, 1);
254 if (iter->second.second == 1) {
255 delete iter->second.first;
256 blob_data_handle_map_.erase(iter);
257 } else {
258 iter->second.second -= 1;
260 } else {
261 DLOG(FATAL) << "Failed to find blob UUID in map:" << uuid;
265 IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
266 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
267 return cursor_dispatcher_host_->map_.Lookup(ipc_cursor_id);
270 ::IndexedDBDatabaseMetadata IndexedDBDispatcherHost::ConvertMetadata(
271 const content::IndexedDBDatabaseMetadata& web_metadata) {
272 ::IndexedDBDatabaseMetadata metadata;
273 metadata.id = web_metadata.id;
274 metadata.name = web_metadata.name;
275 metadata.version = web_metadata.version;
276 metadata.int_version = web_metadata.int_version;
277 metadata.max_object_store_id = web_metadata.max_object_store_id;
279 for (const auto& iter : web_metadata.object_stores) {
280 const content::IndexedDBObjectStoreMetadata& web_store_metadata =
281 iter.second;
282 ::IndexedDBObjectStoreMetadata idb_store_metadata;
283 idb_store_metadata.id = web_store_metadata.id;
284 idb_store_metadata.name = web_store_metadata.name;
285 idb_store_metadata.key_path = web_store_metadata.key_path;
286 idb_store_metadata.auto_increment = web_store_metadata.auto_increment;
287 idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
289 for (const auto& index_iter : web_store_metadata.indexes) {
290 const content::IndexedDBIndexMetadata& web_index_metadata =
291 index_iter.second;
292 ::IndexedDBIndexMetadata idb_index_metadata;
293 idb_index_metadata.id = web_index_metadata.id;
294 idb_index_metadata.name = web_index_metadata.name;
295 idb_index_metadata.key_path = web_index_metadata.key_path;
296 idb_index_metadata.unique = web_index_metadata.unique;
297 idb_index_metadata.multi_entry = web_index_metadata.multi_entry;
298 idb_store_metadata.indexes.push_back(idb_index_metadata);
300 metadata.object_stores.push_back(idb_store_metadata);
302 return metadata;
305 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
306 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) {
307 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
308 base::FilePath indexed_db_path = indexed_db_context_->data_path();
310 GURL origin_url =
311 storage::GetOriginFromIdentifier(params.database_identifier);
313 Context()->GetIDBFactory()->GetDatabaseNames(
314 new IndexedDBCallbacks(
315 this, params.ipc_thread_id, params.ipc_callbacks_id),
316 origin_url,
317 indexed_db_path,
318 request_context_);
321 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
322 const IndexedDBHostMsg_FactoryOpen_Params& params) {
323 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
324 base::TimeTicks begin_time = base::TimeTicks::Now();
325 base::FilePath indexed_db_path = indexed_db_context_->data_path();
327 GURL origin_url =
328 storage::GetOriginFromIdentifier(params.database_identifier);
330 int64 host_transaction_id = HostTransactionId(params.transaction_id);
332 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
333 // created) if this origin is already over quota.
334 scoped_refptr<IndexedDBCallbacks> callbacks =
335 new IndexedDBCallbacks(this,
336 params.ipc_thread_id,
337 params.ipc_callbacks_id,
338 params.ipc_database_callbacks_id,
339 host_transaction_id,
340 origin_url);
341 callbacks->SetConnectionOpenStartTime(begin_time);
342 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
343 new IndexedDBDatabaseCallbacks(
344 this, params.ipc_thread_id, params.ipc_database_callbacks_id);
345 IndexedDBPendingConnection connection(callbacks,
346 database_callbacks,
347 ipc_process_id_,
348 host_transaction_id,
349 params.version);
350 DCHECK(request_context_);
351 Context()->GetIDBFactory()->Open(
352 params.name, connection, request_context_, origin_url, indexed_db_path);
355 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
356 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
357 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
358 GURL origin_url =
359 storage::GetOriginFromIdentifier(params.database_identifier);
360 base::FilePath indexed_db_path = indexed_db_context_->data_path();
361 DCHECK(request_context_);
362 Context()->GetIDBFactory()->DeleteDatabase(
363 params.name,
364 request_context_,
365 new IndexedDBCallbacks(
366 this, params.ipc_thread_id, params.ipc_callbacks_id),
367 origin_url,
368 indexed_db_path);
371 // OnPutHelper exists only to allow us to hop threads while holding a reference
372 // to the IndexedDBDispatcherHost.
373 void IndexedDBDispatcherHost::OnPutHelper(
374 const IndexedDBHostMsg_DatabasePut_Params& params,
375 std::vector<storage::BlobDataHandle*> handles) {
376 database_dispatcher_host_->OnPut(params, handles);
379 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
380 const std::vector<std::string>& uuids) {
381 DCHECK_CURRENTLY_ON(BrowserThread::IO);
382 for (const auto& uuid : uuids)
383 DropBlobData(uuid);
386 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
387 bool committed) {
388 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
389 if (!database_dispatcher_host_)
390 return;
391 TransactionIDToURLMap& transaction_url_map =
392 database_dispatcher_host_->transaction_url_map_;
393 TransactionIDToSizeMap& transaction_size_map =
394 database_dispatcher_host_->transaction_size_map_;
395 TransactionIDToDatabaseIDMap& transaction_database_map =
396 database_dispatcher_host_->transaction_database_map_;
397 if (committed)
398 Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
399 transaction_url_map.erase(host_transaction_id);
400 transaction_size_map.erase(host_transaction_id);
401 transaction_database_map.erase(host_transaction_id);
404 //////////////////////////////////////////////////////////////////////
405 // Helper templates.
408 template <typename ObjectType>
409 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
410 IDMap<ObjectType, IDMapOwnPointer>* map,
411 int32 ipc_return_object_id) {
412 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
413 ObjectType* return_object = map->Lookup(ipc_return_object_id);
414 if (!return_object) {
415 NOTREACHED() << "Uh oh, couldn't find object with id "
416 << ipc_return_object_id;
417 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
418 BadMessageReceived();
420 return return_object;
423 template <typename ObjectType>
424 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
425 RefIDMap<ObjectType>* map,
426 int32 ipc_return_object_id) {
427 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
428 ObjectType* return_object = map->Lookup(ipc_return_object_id);
429 if (!return_object) {
430 NOTREACHED() << "Uh oh, couldn't find object with id "
431 << ipc_return_object_id;
432 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
433 BadMessageReceived();
435 return return_object;
438 template <typename MapType>
439 void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) {
440 GetOrTerminateProcess(map, ipc_object_id);
441 map->Remove(ipc_object_id);
444 //////////////////////////////////////////////////////////////////////
445 // IndexedDBDispatcherHost::DatabaseDispatcherHost
448 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
449 IndexedDBDispatcherHost* parent)
450 : parent_(parent) {
451 map_.set_check_on_null_data(true);
454 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
455 // TODO(alecflett): uncomment these when we find the source of these leaks.
456 // DCHECK(transaction_size_map_.empty());
457 // DCHECK(transaction_url_map_.empty());
460 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
461 DCHECK(
462 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
463 // Abort outstanding transactions started by connections in the associated
464 // front-end to unblock later transactions. This should only occur on unclean
465 // (crash) or abrupt (process-kill) shutdowns.
466 for (TransactionIDToDatabaseIDMap::iterator iter =
467 transaction_database_map_.begin();
468 iter != transaction_database_map_.end();) {
469 int64 transaction_id = iter->first;
470 int32 ipc_database_id = iter->second;
471 ++iter;
472 IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
473 if (connection && connection->IsConnected()) {
474 connection->database()->Abort(
475 transaction_id,
476 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError));
479 DCHECK(transaction_database_map_.empty());
481 for (const auto& iter : database_url_map_) {
482 IndexedDBConnection* connection = map_.Lookup(iter.first);
483 if (connection && connection->IsConnected()) {
484 connection->Close();
485 parent_->Context()->ConnectionClosed(iter.second, connection);
490 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
491 const IPC::Message& message) {
492 DCHECK(
493 (message.type() == IndexedDBHostMsg_DatabasePut::ID ||
494 message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID) ||
495 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
497 bool handled = true;
498 IPC_BEGIN_MESSAGE_MAP(
499 IndexedDBDispatcherHost::DatabaseDispatcherHost, message)
500 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
501 OnCreateObjectStore)
502 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
503 OnDeleteObjectStore)
504 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
505 OnCreateTransaction)
506 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
507 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored,
508 OnVersionChangeIgnored)
509 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
510 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
511 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
512 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
513 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
514 OnSetIndexesReady)
515 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor)
516 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount)
517 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange)
518 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear)
519 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex)
520 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex)
521 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort)
522 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit)
523 IPC_MESSAGE_UNHANDLED(handled = false)
524 IPC_END_MESSAGE_MAP()
526 return handled;
529 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
530 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
531 DCHECK(
532 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
533 IndexedDBConnection* connection =
534 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
535 if (!connection || !connection->IsConnected())
536 return;
538 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
539 connection->database()->CreateObjectStore(host_transaction_id,
540 params.object_store_id,
541 params.name,
542 params.key_path,
543 params.auto_increment);
544 if (parent_->Context()->IsOverQuota(
545 database_url_map_[params.ipc_database_id])) {
546 connection->database()->Abort(
547 host_transaction_id,
548 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
552 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
553 int32 ipc_database_id,
554 int64 transaction_id,
555 int64 object_store_id) {
556 DCHECK(
557 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
558 IndexedDBConnection* connection =
559 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
560 if (!connection || !connection->IsConnected())
561 return;
563 connection->database()->DeleteObjectStore(
564 parent_->HostTransactionId(transaction_id), object_store_id);
567 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
568 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
569 DCHECK(
570 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
571 IndexedDBConnection* connection =
572 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
573 if (!connection || !connection->IsConnected())
574 return;
576 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
578 if (transaction_database_map_.find(host_transaction_id) !=
579 transaction_database_map_.end()) {
580 DLOG(ERROR) << "Duplicate host_transaction_id.";
581 return;
584 connection->database()->CreateTransaction(
585 host_transaction_id, connection, params.object_store_ids, params.mode);
586 transaction_database_map_[host_transaction_id] = params.ipc_database_id;
587 parent_->RegisterTransactionId(host_transaction_id,
588 database_url_map_[params.ipc_database_id]);
591 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
592 int32 ipc_database_id) {
593 DCHECK(
594 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
595 IndexedDBConnection* connection =
596 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
597 if (!connection || !connection->IsConnected())
598 return;
599 connection->Close();
602 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
603 int32 ipc_database_id) {
604 DCHECK(
605 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
606 IndexedDBConnection* connection =
607 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
608 if (!connection || !connection->IsConnected())
609 return;
610 connection->VersionChangeIgnored();
613 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
614 int32 ipc_object_id) {
615 DCHECK(
616 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
617 IndexedDBConnection* connection =
618 parent_->GetOrTerminateProcess(&map_, ipc_object_id);
619 if (!connection)
620 return;
621 if (connection->IsConnected())
622 connection->Close();
623 parent_->Context()
624 ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
625 database_url_map_.erase(ipc_object_id);
626 parent_->DestroyObject(&map_, ipc_object_id);
629 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
630 const IndexedDBHostMsg_DatabaseGet_Params& params) {
631 DCHECK(
632 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
633 IndexedDBConnection* connection =
634 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
635 if (!connection || !connection->IsConnected())
636 return;
638 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
639 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
640 connection->database()->Get(
641 parent_->HostTransactionId(params.transaction_id),
642 params.object_store_id,
643 params.index_id,
644 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
645 params.key_only,
646 callbacks);
649 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
650 const IndexedDBHostMsg_DatabasePut_Params& params) {
651 std::vector<storage::BlobDataHandle*> handles;
652 for (size_t i = 0; i < params.value.blob_or_file_info.size(); ++i) {
653 const IndexedDBMsg_BlobOrFileInfo& info = params.value.blob_or_file_info[i];
654 handles.push_back(parent_->blob_storage_context_->context()
655 ->GetBlobDataFromUUID(info.uuid)
656 .release());
658 parent_->indexed_db_context_->TaskRunner()->PostTask(
659 FROM_HERE,
660 base::Bind(
661 &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
664 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
665 const IndexedDBHostMsg_DatabasePut_Params& params,
666 std::vector<storage::BlobDataHandle*> handles) {
667 DCHECK(
668 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
670 ScopedVector<storage::BlobDataHandle> scoped_handles;
671 scoped_handles.swap(handles);
673 IndexedDBConnection* connection =
674 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
675 if (!connection || !connection->IsConnected())
676 return;
677 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
678 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
680 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
682 std::vector<IndexedDBBlobInfo> blob_info(
683 params.value.blob_or_file_info.size());
685 ChildProcessSecurityPolicyImpl* policy =
686 ChildProcessSecurityPolicyImpl::GetInstance();
688 for (size_t i = 0; i < params.value.blob_or_file_info.size(); ++i) {
689 const IndexedDBMsg_BlobOrFileInfo& info = params.value.blob_or_file_info[i];
690 if (info.is_file) {
691 base::FilePath path;
692 if (!info.file_path.empty()) {
693 path = base::FilePath::FromUTF16Unsafe(info.file_path);
694 if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
695 parent_->BadMessageReceived();
696 return;
699 blob_info[i] =
700 IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type);
701 if (info.size != static_cast<uint64_t>(-1)) {
702 blob_info[i].set_last_modified(
703 base::Time::FromDoubleT(info.last_modified));
704 blob_info[i].set_size(info.size);
706 } else {
707 blob_info[i] = IndexedDBBlobInfo(info.uuid, info.mime_type, info.size);
711 // TODO(alecflett): Avoid a copy here.
712 IndexedDBValue value;
713 value.bits = params.value.bits;
714 value.blob_info.swap(blob_info);
715 connection->database()->Put(host_transaction_id,
716 params.object_store_id,
717 &value,
718 &scoped_handles,
719 make_scoped_ptr(new IndexedDBKey(params.key)),
720 params.put_mode,
721 callbacks,
722 params.index_keys);
723 TransactionIDToSizeMap* map =
724 &parent_->database_dispatcher_host_->transaction_size_map_;
725 // Size can't be big enough to overflow because it represents the
726 // actual bytes passed through IPC.
727 (*map)[host_transaction_id] += params.value.bits.size();
730 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
731 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
732 DCHECK(
733 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
734 IndexedDBConnection* connection =
735 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
736 if (!connection || !connection->IsConnected())
737 return;
739 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
740 connection->database()->SetIndexKeys(
741 host_transaction_id,
742 params.object_store_id,
743 make_scoped_ptr(new IndexedDBKey(params.primary_key)),
744 params.index_keys);
747 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
748 int32 ipc_database_id,
749 int64 transaction_id,
750 int64 object_store_id,
751 const std::vector<int64>& index_ids) {
752 DCHECK(
753 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
754 IndexedDBConnection* connection =
755 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
756 if (!connection || !connection->IsConnected())
757 return;
759 connection->database()->SetIndexesReady(
760 parent_->HostTransactionId(transaction_id), object_store_id, index_ids);
763 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
764 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
765 DCHECK(
766 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
767 IndexedDBConnection* connection =
768 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
769 if (!connection || !connection->IsConnected())
770 return;
772 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
773 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1));
774 connection->database()->OpenCursor(
775 parent_->HostTransactionId(params.transaction_id),
776 params.object_store_id,
777 params.index_id,
778 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
779 params.direction,
780 params.key_only,
781 params.task_type,
782 callbacks);
785 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
786 const IndexedDBHostMsg_DatabaseCount_Params& params) {
787 DCHECK(
788 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
789 IndexedDBConnection* connection =
790 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
791 if (!connection || !connection->IsConnected())
792 return;
794 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
795 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
796 connection->database()->Count(
797 parent_->HostTransactionId(params.transaction_id),
798 params.object_store_id,
799 params.index_id,
800 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
801 callbacks);
804 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
805 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
806 DCHECK(
807 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
808 IndexedDBConnection* connection =
809 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
810 if (!connection || !connection->IsConnected())
811 return;
813 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
814 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
815 connection->database()->DeleteRange(
816 parent_->HostTransactionId(params.transaction_id),
817 params.object_store_id,
818 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
819 callbacks);
822 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
823 int32 ipc_thread_id,
824 int32 ipc_callbacks_id,
825 int32 ipc_database_id,
826 int64 transaction_id,
827 int64 object_store_id) {
828 DCHECK(
829 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
830 IndexedDBConnection* connection =
831 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
832 if (!connection || !connection->IsConnected())
833 return;
835 scoped_refptr<IndexedDBCallbacks> callbacks(
836 new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id));
838 connection->database()->Clear(
839 parent_->HostTransactionId(transaction_id), object_store_id, callbacks);
842 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
843 int32 ipc_database_id,
844 int64 transaction_id) {
845 DCHECK(
846 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
847 IndexedDBConnection* connection =
848 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
849 if (!connection || !connection->IsConnected())
850 return;
852 connection->database()->Abort(parent_->HostTransactionId(transaction_id));
855 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
856 int32 ipc_database_id,
857 int64 transaction_id) {
858 DCHECK(
859 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
860 IndexedDBConnection* connection =
861 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
862 if (!connection || !connection->IsConnected())
863 return;
865 int64 host_transaction_id = parent_->HostTransactionId(transaction_id);
866 int64 transaction_size = transaction_size_map_[host_transaction_id];
867 if (transaction_size &&
868 parent_->Context()->WouldBeOverQuota(
869 transaction_url_map_[host_transaction_id], transaction_size)) {
870 connection->database()->Abort(
871 host_transaction_id,
872 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
873 return;
876 connection->database()->Commit(host_transaction_id);
879 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
880 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
881 DCHECK(
882 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
883 IndexedDBConnection* connection =
884 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
885 if (!connection || !connection->IsConnected())
886 return;
888 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
889 connection->database()->CreateIndex(host_transaction_id,
890 params.object_store_id,
891 params.index_id,
892 params.name,
893 params.key_path,
894 params.unique,
895 params.multi_entry);
896 if (parent_->Context()->IsOverQuota(
897 database_url_map_[params.ipc_database_id])) {
898 connection->database()->Abort(
899 host_transaction_id,
900 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
904 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
905 int32 ipc_database_id,
906 int64 transaction_id,
907 int64 object_store_id,
908 int64 index_id) {
909 DCHECK(
910 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
911 IndexedDBConnection* connection =
912 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
913 if (!connection || !connection->IsConnected())
914 return;
916 connection->database()->DeleteIndex(
917 parent_->HostTransactionId(transaction_id), object_store_id, index_id);
920 //////////////////////////////////////////////////////////////////////
921 // IndexedDBDispatcherHost::CursorDispatcherHost
924 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
925 IndexedDBDispatcherHost* parent)
926 : parent_(parent) {
927 map_.set_check_on_null_data(true);
930 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
932 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
933 const IPC::Message& message) {
934 bool handled = true;
935 IPC_BEGIN_MESSAGE_MAP(
936 IndexedDBDispatcherHost::CursorDispatcherHost, message)
937 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance)
938 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
939 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch)
940 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset)
941 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
942 IPC_MESSAGE_UNHANDLED(handled = false)
943 IPC_END_MESSAGE_MAP()
945 DCHECK(
946 !handled ||
947 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
949 return handled;
952 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
953 int32 ipc_cursor_id,
954 int32 ipc_thread_id,
955 int32 ipc_callbacks_id,
956 uint32 count) {
957 DCHECK(
958 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
959 IndexedDBCursor* idb_cursor =
960 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
961 if (!idb_cursor)
962 return;
964 idb_cursor->Advance(
965 count,
966 new IndexedDBCallbacks(
967 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
970 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
971 int32 ipc_cursor_id,
972 int32 ipc_thread_id,
973 int32 ipc_callbacks_id,
974 const IndexedDBKey& key,
975 const IndexedDBKey& primary_key) {
976 DCHECK(
977 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
978 IndexedDBCursor* idb_cursor =
979 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
980 if (!idb_cursor)
981 return;
983 idb_cursor->Continue(
984 key.IsValid() ? make_scoped_ptr(new IndexedDBKey(key))
985 : scoped_ptr<IndexedDBKey>(),
986 primary_key.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key))
987 : scoped_ptr<IndexedDBKey>(),
988 new IndexedDBCallbacks(
989 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
992 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
993 int32 ipc_cursor_id,
994 int32 ipc_thread_id,
995 int32 ipc_callbacks_id,
996 int n) {
997 DCHECK(
998 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
999 IndexedDBCursor* idb_cursor =
1000 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
1001 if (!idb_cursor)
1002 return;
1004 idb_cursor->PrefetchContinue(
1006 new IndexedDBCallbacks(
1007 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
1010 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
1011 int32 ipc_cursor_id,
1012 int used_prefetches,
1013 int unused_prefetches) {
1014 DCHECK(
1015 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
1016 IndexedDBCursor* idb_cursor =
1017 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
1018 if (!idb_cursor)
1019 return;
1021 leveldb::Status s =
1022 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
1023 // TODO(cmumford): Handle this error (crbug.com/363397)
1024 if (!s.ok())
1025 DLOG(ERROR) << "Unable to reset prefetch";
1028 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
1029 int32 ipc_object_id) {
1030 DCHECK(
1031 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
1032 parent_->DestroyObject(&map_, ipc_object_id);
1035 } // namespace content