[Mac] Implement Ambient Light API
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_dispatcher_host.cc
blob7a4b40134044fddc321e5762093df109a9471bcf
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_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"
34 #include "url/gurl.h"
36 using storage::DatabaseUtil;
37 using blink::WebIDBKey;
39 namespace content {
41 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
42 int ipc_process_id,
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(
58 int ipc_process_id,
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(
90 FROM_HERE,
91 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this));
93 if (!success)
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)
124 return NULL;
126 switch (message.type()) {
127 case IndexedDBHostMsg_DatabasePut::ID:
128 case IndexedDBHostMsg_AckReceivedBlobs::ID:
129 return NULL;
130 default:
131 return indexed_db_context_->TaskRunner();
135 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
136 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
137 return false;
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);
146 if (!handled) {
147 handled = true;
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()
158 return handled;
161 int32 IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) {
162 if (!cursor_dispatcher_host_) {
163 return 0;
165 return cursor_dispatcher_host_->map_.Add(cursor);
168 int32 IndexedDBDispatcherHost::Add(IndexedDBConnection* connection,
169 int32 ipc_thread_id,
170 const GURL& origin_url) {
171 if (!database_dispatcher_host_) {
172 connection->Close();
173 delete connection;
174 return -1;
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,
183 const GURL& url) {
184 if (!database_dispatcher_host_)
185 return;
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;
209 // static
210 uint32 IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
211 int64 host_transaction_id) {
212 return host_transaction_id & 0xffffffff;
215 // static
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;
227 if (uuid.empty()) {
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());
234 } else {
235 auto iter = blob_data_handle_map_.find(uuid);
236 if (iter != blob_data_handle_map_.end()) {
237 iter->second.second += 1;
238 return uuid;
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);
245 return uuid;
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);
256 } else {
257 iter->second.second -= 1;
259 } else {
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 =
280 iter.second;
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 =
290 index_iter.second;
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);
301 return 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();
309 GURL origin_url =
310 storage::GetOriginFromIdentifier(params.database_identifier);
312 Context()->GetIDBFactory()->GetDatabaseNames(
313 new IndexedDBCallbacks(
314 this, params.ipc_thread_id, params.ipc_callbacks_id),
315 origin_url,
316 indexed_db_path,
317 request_context_);
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();
326 GURL origin_url =
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,
338 host_transaction_id,
339 origin_url);
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,
345 database_callbacks,
346 ipc_process_id_,
347 host_transaction_id,
348 params.version);
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());
357 GURL origin_url =
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(
362 params.name,
363 request_context_,
364 new IndexedDBCallbacks(
365 this, params.ipc_thread_id, params.ipc_callbacks_id),
366 origin_url,
367 indexed_db_path);
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)
382 DropBlobData(uuid);
385 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
386 bool committed) {
387 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
388 if (!database_dispatcher_host_)
389 return;
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_;
396 if (committed)
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 //////////////////////////////////////////////////////////////////////
404 // Helper templates.
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)
449 : parent_(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() {
460 DCHECK(
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;
470 ++iter;
471 IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
472 if (connection && connection->IsConnected()) {
473 connection->database()->Abort(
474 transaction_id,
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()) {
483 connection->Close();
484 parent_->Context()->ConnectionClosed(iter.second, connection);
489 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
490 const IPC::Message& message) {
491 DCHECK(
492 (message.type() == IndexedDBHostMsg_DatabasePut::ID ||
493 message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID) ||
494 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
496 bool handled = true;
497 IPC_BEGIN_MESSAGE_MAP(
498 IndexedDBDispatcherHost::DatabaseDispatcherHost, message)
499 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
500 OnCreateObjectStore)
501 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
502 OnDeleteObjectStore)
503 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
504 OnCreateTransaction)
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,
513 OnSetIndexesReady)
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()
525 return handled;
528 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
529 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
530 DCHECK(
531 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
532 IndexedDBConnection* connection =
533 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
534 if (!connection || !connection->IsConnected())
535 return;
537 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
538 connection->database()->CreateObjectStore(host_transaction_id,
539 params.object_store_id,
540 params.name,
541 params.key_path,
542 params.auto_increment);
543 if (parent_->Context()->IsOverQuota(
544 database_url_map_[params.ipc_database_id])) {
545 connection->database()->Abort(
546 host_transaction_id,
547 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
551 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
552 int32 ipc_database_id,
553 int64 transaction_id,
554 int64 object_store_id) {
555 DCHECK(
556 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
557 IndexedDBConnection* connection =
558 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
559 if (!connection || !connection->IsConnected())
560 return;
562 connection->database()->DeleteObjectStore(
563 parent_->HostTransactionId(transaction_id), object_store_id);
566 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
567 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
568 DCHECK(
569 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
570 IndexedDBConnection* connection =
571 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
572 if (!connection || !connection->IsConnected())
573 return;
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.";
580 return;
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) {
592 DCHECK(
593 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
594 IndexedDBConnection* connection =
595 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
596 if (!connection || !connection->IsConnected())
597 return;
598 connection->Close();
601 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
602 int32 ipc_database_id) {
603 DCHECK(
604 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
605 IndexedDBConnection* connection =
606 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
607 if (!connection || !connection->IsConnected())
608 return;
609 connection->VersionChangeIgnored();
612 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
613 int32 ipc_object_id) {
614 DCHECK(
615 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
616 IndexedDBConnection* connection = map_.Lookup(ipc_object_id);
617 if (connection->IsConnected())
618 connection->Close();
619 parent_->Context()
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) {
627 DCHECK(
628 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
629 IndexedDBConnection* connection =
630 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
631 if (!connection || !connection->IsConnected())
632 return;
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,
639 params.index_id,
640 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
641 params.key_only,
642 callbacks);
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)
652 .release());
654 parent_->indexed_db_context_->TaskRunner()->PostTask(
655 FROM_HERE,
656 base::Bind(
657 &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
660 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
661 const IndexedDBHostMsg_DatabasePut_Params& params,
662 std::vector<storage::BlobDataHandle*> handles) {
663 DCHECK(
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())
672 return;
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];
685 if (info.is_file) {
686 base::FilePath path;
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();
691 return;
694 blob_info[i] =
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);
701 } else {
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,
712 &value,
713 &scoped_handles,
714 make_scoped_ptr(new IndexedDBKey(params.key)),
715 params.put_mode,
716 callbacks,
717 params.index_keys);
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) {
727 DCHECK(
728 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
729 IndexedDBConnection* connection =
730 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
731 if (!connection || !connection->IsConnected())
732 return;
734 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
735 connection->database()->SetIndexKeys(
736 host_transaction_id,
737 params.object_store_id,
738 make_scoped_ptr(new IndexedDBKey(params.primary_key)),
739 params.index_keys);
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) {
747 DCHECK(
748 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
749 IndexedDBConnection* connection =
750 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
751 if (!connection || !connection->IsConnected())
752 return;
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) {
760 DCHECK(
761 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
762 IndexedDBConnection* connection =
763 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
764 if (!connection || !connection->IsConnected())
765 return;
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,
772 params.index_id,
773 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
774 params.direction,
775 params.key_only,
776 params.task_type,
777 callbacks);
780 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
781 const IndexedDBHostMsg_DatabaseCount_Params& params) {
782 DCHECK(
783 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
784 IndexedDBConnection* connection =
785 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
786 if (!connection || !connection->IsConnected())
787 return;
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,
794 params.index_id,
795 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
796 callbacks);
799 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
800 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
801 DCHECK(
802 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
803 IndexedDBConnection* connection =
804 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
805 if (!connection || !connection->IsConnected())
806 return;
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)),
814 callbacks);
817 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
818 int32 ipc_thread_id,
819 int32 ipc_callbacks_id,
820 int32 ipc_database_id,
821 int64 transaction_id,
822 int64 object_store_id) {
823 DCHECK(
824 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
825 IndexedDBConnection* connection =
826 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
827 if (!connection || !connection->IsConnected())
828 return;
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) {
840 DCHECK(
841 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
842 IndexedDBConnection* connection =
843 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
844 if (!connection || !connection->IsConnected())
845 return;
847 connection->database()->Abort(parent_->HostTransactionId(transaction_id));
850 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
851 int32 ipc_database_id,
852 int64 transaction_id) {
853 DCHECK(
854 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
855 IndexedDBConnection* connection =
856 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
857 if (!connection || !connection->IsConnected())
858 return;
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(
866 host_transaction_id,
867 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
868 return;
871 connection->database()->Commit(host_transaction_id);
874 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
875 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
876 DCHECK(
877 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
878 IndexedDBConnection* connection =
879 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
880 if (!connection || !connection->IsConnected())
881 return;
883 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
884 connection->database()->CreateIndex(host_transaction_id,
885 params.object_store_id,
886 params.index_id,
887 params.name,
888 params.key_path,
889 params.unique,
890 params.multi_entry);
891 if (parent_->Context()->IsOverQuota(
892 database_url_map_[params.ipc_database_id])) {
893 connection->database()->Abort(
894 host_transaction_id,
895 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
899 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
900 int32 ipc_database_id,
901 int64 transaction_id,
902 int64 object_store_id,
903 int64 index_id) {
904 DCHECK(
905 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
906 IndexedDBConnection* connection =
907 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
908 if (!connection || !connection->IsConnected())
909 return;
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)
921 : parent_(parent) {
922 map_.set_check_on_null_data(true);
925 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
927 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
928 const IPC::Message& message) {
929 bool handled = true;
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()
940 DCHECK(
941 !handled ||
942 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
944 return handled;
947 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
948 int32 ipc_cursor_id,
949 int32 ipc_thread_id,
950 int32 ipc_callbacks_id,
951 uint32 count) {
952 DCHECK(
953 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
954 IndexedDBCursor* idb_cursor =
955 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
956 if (!idb_cursor)
957 return;
959 idb_cursor->Advance(
960 count,
961 new IndexedDBCallbacks(
962 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
965 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
966 int32 ipc_cursor_id,
967 int32 ipc_thread_id,
968 int32 ipc_callbacks_id,
969 const IndexedDBKey& key,
970 const IndexedDBKey& primary_key) {
971 DCHECK(
972 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
973 IndexedDBCursor* idb_cursor =
974 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
975 if (!idb_cursor)
976 return;
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(
988 int32 ipc_cursor_id,
989 int32 ipc_thread_id,
990 int32 ipc_callbacks_id,
991 int n) {
992 DCHECK(
993 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
994 IndexedDBCursor* idb_cursor =
995 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
996 if (!idb_cursor)
997 return;
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) {
1009 DCHECK(
1010 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
1011 IndexedDBCursor* idb_cursor =
1012 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
1013 if (!idb_cursor)
1014 return;
1016 leveldb::Status s =
1017 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
1018 // TODO(cmumford): Handle this error (crbug.com/363397)
1019 if (!s.ok())
1020 DLOG(ERROR) << "Unable to reset prefetch";
1023 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
1024 int32 ipc_object_id) {
1025 DCHECK(
1026 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
1027 parent_->DestroyObject(&map_, ipc_object_id);
1030 } // namespace content