• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
6 
7 #include "base/bind.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"
33 #include "url/gurl.h"
34 
35 using storage::DatabaseUtil;
36 using blink::WebIDBKey;
37 
38 namespace content {
39 
IndexedDBDispatcherHost(int ipc_process_id,net::URLRequestContextGetter * request_context_getter,IndexedDBContextImpl * indexed_db_context,ChromeBlobStorageContext * blob_storage_context)40 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
41     int ipc_process_id,
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());
54 }
55 
IndexedDBDispatcherHost(int ipc_process_id,net::URLRequestContext * request_context,IndexedDBContextImpl * indexed_db_context,ChromeBlobStorageContext * blob_storage_context)56 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
57     int ipc_process_id,
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());
69 }
70 
~IndexedDBDispatcherHost()71 IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
72   STLDeleteValues(&blob_data_handle_map_);
73 }
74 
OnChannelConnected(int32 peer_pid)75 void IndexedDBDispatcherHost::OnChannelConnected(int32 peer_pid) {
76   BrowserMessageFilter::OnChannelConnected(peer_pid);
77 
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_);
83   }
84 }
85 
OnChannelClosing()86 void IndexedDBDispatcherHost::OnChannelClosing() {
87   bool success = indexed_db_context_->TaskRunner()->PostTask(
88       FROM_HERE,
89       base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this));
90 
91   if (!success)
92     ResetDispatcherHosts();
93 }
94 
OnDestruct() const95 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);
102 }
103 
ResetDispatcherHosts()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());
110 
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();
117 }
118 
OverrideTaskRunnerForMessage(const IPC::Message & message)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();
124   return NULL;
125 }
126 
OnMessageReceived(const IPC::Message & message)127 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
128   if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
129     return false;
130 
131   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread() ||
132          message.type() == IndexedDBHostMsg_DatabasePut::ID);
133 
134   bool handled = database_dispatcher_host_->OnMessageReceived(message) ||
135                  cursor_dispatcher_host_->OnMessageReceived(message);
136 
137   if (!handled) {
138     handled = true;
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()
148   }
149   return handled;
150 }
151 
Add(IndexedDBCursor * cursor)152 int32 IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) {
153   if (!cursor_dispatcher_host_) {
154     return 0;
155   }
156   return cursor_dispatcher_host_->map_.Add(cursor);
157 }
158 
Add(IndexedDBConnection * connection,int32 ipc_thread_id,const GURL & origin_url)159 int32 IndexedDBDispatcherHost::Add(IndexedDBConnection* connection,
160                                    int32 ipc_thread_id,
161                                    const GURL& origin_url) {
162   if (!database_dispatcher_host_) {
163     connection->Close();
164     delete connection;
165     return -1;
166   }
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;
171 }
172 
RegisterTransactionId(int64 host_transaction_id,const GURL & url)173 void IndexedDBDispatcherHost::RegisterTransactionId(int64 host_transaction_id,
174                                                     const GURL& url) {
175   if (!database_dispatcher_host_)
176     return;
177   database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url;
178 }
179 
HostTransactionId(int64 transaction_id)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);
189 
190   return transaction_id | (static_cast<uint64>(pid) << 32);
191 }
192 
RendererTransactionId(int64 host_transaction_id)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;
198 }
199 
200 // static
TransactionIdToRendererTransactionId(int64 host_transaction_id)201 uint32 IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
202     int64 host_transaction_id) {
203   return host_transaction_id & 0xffffffff;
204 }
205 
206 // static
TransactionIdToProcessId(int64 host_transaction_id)207 uint32 IndexedDBDispatcherHost::TransactionIdToProcessId(
208     int64 host_transaction_id) {
209   return (host_transaction_id >> 32) & 0xffffffff;
210 }
211 
HoldBlobDataHandle(const std::string & uuid,scoped_ptr<storage::BlobDataHandle> blob_data_handle)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();
217 }
218 
DropBlobDataHandle(const std::string & uuid)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()) {
222     delete iter->second;
223     blob_data_handle_map_.erase(iter);
224   } else {
225     DLOG(FATAL) << "Failed to find blob UUID in map:" << uuid;
226   }
227 }
228 
GetCursorFromId(int32 ipc_cursor_id)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);
232 }
233 
ConvertMetadata(const content::IndexedDBDatabaseMetadata & web_metadata)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;
242 
243   for (content::IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator iter =
244            web_metadata.object_stores.begin();
245        iter != web_metadata.object_stores.end();
246        ++iter) {
247     const content::IndexedDBObjectStoreMetadata& web_store_metadata =
248         iter->second;
249     ::IndexedDBObjectStoreMetadata idb_store_metadata;
250     idb_store_metadata.id = web_store_metadata.id;
251     idb_store_metadata.name = web_store_metadata.name;
252     idb_store_metadata.keyPath = web_store_metadata.key_path;
253     idb_store_metadata.autoIncrement = web_store_metadata.auto_increment;
254     idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
255 
256     for (content::IndexedDBObjectStoreMetadata::IndexMap::const_iterator
257              index_iter = web_store_metadata.indexes.begin();
258          index_iter != web_store_metadata.indexes.end();
259          ++index_iter) {
260       const content::IndexedDBIndexMetadata& web_index_metadata =
261           index_iter->second;
262       ::IndexedDBIndexMetadata idb_index_metadata;
263       idb_index_metadata.id = web_index_metadata.id;
264       idb_index_metadata.name = web_index_metadata.name;
265       idb_index_metadata.keyPath = web_index_metadata.key_path;
266       idb_index_metadata.unique = web_index_metadata.unique;
267       idb_index_metadata.multiEntry = web_index_metadata.multi_entry;
268       idb_store_metadata.indexes.push_back(idb_index_metadata);
269     }
270     metadata.object_stores.push_back(idb_store_metadata);
271   }
272   return metadata;
273 }
274 
OnIDBFactoryGetDatabaseNames(const IndexedDBHostMsg_FactoryGetDatabaseNames_Params & params)275 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
276     const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) {
277   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
278   base::FilePath indexed_db_path = indexed_db_context_->data_path();
279 
280   GURL origin_url =
281       storage::GetOriginFromIdentifier(params.database_identifier);
282 
283   Context()->GetIDBFactory()->GetDatabaseNames(
284       new IndexedDBCallbacks(
285           this, params.ipc_thread_id, params.ipc_callbacks_id),
286       origin_url,
287       indexed_db_path,
288       request_context_);
289 }
290 
OnIDBFactoryOpen(const IndexedDBHostMsg_FactoryOpen_Params & params)291 void IndexedDBDispatcherHost::OnIDBFactoryOpen(
292     const IndexedDBHostMsg_FactoryOpen_Params& params) {
293   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
294   base::TimeTicks begin_time = base::TimeTicks::Now();
295   base::FilePath indexed_db_path = indexed_db_context_->data_path();
296 
297   GURL origin_url =
298       storage::GetOriginFromIdentifier(params.database_identifier);
299 
300   int64 host_transaction_id = HostTransactionId(params.transaction_id);
301 
302   // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
303   // created) if this origin is already over quota.
304   scoped_refptr<IndexedDBCallbacks> callbacks =
305       new IndexedDBCallbacks(this,
306                              params.ipc_thread_id,
307                              params.ipc_callbacks_id,
308                              params.ipc_database_callbacks_id,
309                              host_transaction_id,
310                              origin_url);
311   callbacks->SetConnectionOpenStartTime(begin_time);
312   scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
313       new IndexedDBDatabaseCallbacks(
314           this, params.ipc_thread_id, params.ipc_database_callbacks_id);
315   IndexedDBPendingConnection connection(callbacks,
316                                         database_callbacks,
317                                         ipc_process_id_,
318                                         host_transaction_id,
319                                         params.version);
320   DCHECK(request_context_);
321   Context()->GetIDBFactory()->Open(
322       params.name, connection, request_context_, origin_url, indexed_db_path);
323 }
324 
OnIDBFactoryDeleteDatabase(const IndexedDBHostMsg_FactoryDeleteDatabase_Params & params)325 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
326     const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
327   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
328   GURL origin_url =
329       storage::GetOriginFromIdentifier(params.database_identifier);
330   base::FilePath indexed_db_path = indexed_db_context_->data_path();
331   DCHECK(request_context_);
332   Context()->GetIDBFactory()->DeleteDatabase(
333       params.name,
334       request_context_,
335       new IndexedDBCallbacks(
336           this, params.ipc_thread_id, params.ipc_callbacks_id),
337       origin_url,
338       indexed_db_path);
339 }
340 
341 // OnPutHelper exists only to allow us to hop threads while holding a reference
342 // to the IndexedDBDispatcherHost.
OnPutHelper(const IndexedDBHostMsg_DatabasePut_Params & params,std::vector<storage::BlobDataHandle * > handles)343 void IndexedDBDispatcherHost::OnPutHelper(
344     const IndexedDBHostMsg_DatabasePut_Params& params,
345     std::vector<storage::BlobDataHandle*> handles) {
346   database_dispatcher_host_->OnPut(params, handles);
347 }
348 
OnAckReceivedBlobs(const std::vector<std::string> & uuids)349 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
350     const std::vector<std::string>& uuids) {
351   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
352   std::vector<std::string>::const_iterator iter;
353   for (iter = uuids.begin(); iter != uuids.end(); ++iter)
354     DropBlobDataHandle(*iter);
355 }
356 
FinishTransaction(int64 host_transaction_id,bool committed)357 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
358                                                 bool committed) {
359   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
360   if (!database_dispatcher_host_)
361     return;
362   TransactionIDToURLMap& transaction_url_map =
363       database_dispatcher_host_->transaction_url_map_;
364   TransactionIDToSizeMap& transaction_size_map =
365       database_dispatcher_host_->transaction_size_map_;
366   TransactionIDToDatabaseIDMap& transaction_database_map =
367       database_dispatcher_host_->transaction_database_map_;
368   if (committed)
369     Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
370   transaction_url_map.erase(host_transaction_id);
371   transaction_size_map.erase(host_transaction_id);
372   transaction_database_map.erase(host_transaction_id);
373 }
374 
375 //////////////////////////////////////////////////////////////////////
376 // Helper templates.
377 //
378 
379 template <typename ObjectType>
GetOrTerminateProcess(IDMap<ObjectType,IDMapOwnPointer> * map,int32 ipc_return_object_id)380 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
381     IDMap<ObjectType, IDMapOwnPointer>* map,
382     int32 ipc_return_object_id) {
383   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
384   ObjectType* return_object = map->Lookup(ipc_return_object_id);
385   if (!return_object) {
386     NOTREACHED() << "Uh oh, couldn't find object with id "
387                  << ipc_return_object_id;
388     RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
389     BadMessageReceived();
390   }
391   return return_object;
392 }
393 
394 template <typename ObjectType>
GetOrTerminateProcess(RefIDMap<ObjectType> * map,int32 ipc_return_object_id)395 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
396     RefIDMap<ObjectType>* map,
397     int32 ipc_return_object_id) {
398   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
399   ObjectType* return_object = map->Lookup(ipc_return_object_id);
400   if (!return_object) {
401     NOTREACHED() << "Uh oh, couldn't find object with id "
402                  << ipc_return_object_id;
403     RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
404     BadMessageReceived();
405   }
406   return return_object;
407 }
408 
409 template <typename MapType>
DestroyObject(MapType * map,int32 ipc_object_id)410 void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) {
411   GetOrTerminateProcess(map, ipc_object_id);
412   map->Remove(ipc_object_id);
413 }
414 
415 //////////////////////////////////////////////////////////////////////
416 // IndexedDBDispatcherHost::DatabaseDispatcherHost
417 //
418 
DatabaseDispatcherHost(IndexedDBDispatcherHost * parent)419 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
420     IndexedDBDispatcherHost* parent)
421     : parent_(parent) {
422   map_.set_check_on_null_data(true);
423 }
424 
~DatabaseDispatcherHost()425 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
426   // TODO(alecflett): uncomment these when we find the source of these leaks.
427   // DCHECK(transaction_size_map_.empty());
428   // DCHECK(transaction_url_map_.empty());
429 }
430 
CloseAll()431 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
432   DCHECK(
433       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
434   // Abort outstanding transactions started by connections in the associated
435   // front-end to unblock later transactions. This should only occur on unclean
436   // (crash) or abrupt (process-kill) shutdowns.
437   for (TransactionIDToDatabaseIDMap::iterator iter =
438            transaction_database_map_.begin();
439        iter != transaction_database_map_.end();) {
440     int64 transaction_id = iter->first;
441     int32 ipc_database_id = iter->second;
442     ++iter;
443     IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
444     if (connection && connection->IsConnected()) {
445       connection->database()->Abort(
446           transaction_id,
447           IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError));
448     }
449   }
450   DCHECK(transaction_database_map_.empty());
451 
452   for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin();
453        iter != database_url_map_.end();
454        iter++) {
455     IndexedDBConnection* connection = map_.Lookup(iter->first);
456     if (connection && connection->IsConnected()) {
457       connection->Close();
458       parent_->Context()->ConnectionClosed(iter->second, connection);
459     }
460   }
461 }
462 
OnMessageReceived(const IPC::Message & message)463 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
464     const IPC::Message& message) {
465 
466   DCHECK(
467       (message.type() == IndexedDBHostMsg_DatabasePut::ID) ||
468       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
469 
470   bool handled = true;
471   IPC_BEGIN_MESSAGE_MAP(
472       IndexedDBDispatcherHost::DatabaseDispatcherHost, message)
473     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
474                         OnCreateObjectStore)
475     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
476                         OnDeleteObjectStore)
477     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
478                         OnCreateTransaction)
479     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
480     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored,
481                         OnVersionChangeIgnored)
482     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
483     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
484     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
485     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
486     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
487                         OnSetIndexesReady)
488     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor)
489     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount)
490     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange)
491     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear)
492     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex)
493     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex)
494     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort)
495     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit)
496     IPC_MESSAGE_UNHANDLED(handled = false)
497   IPC_END_MESSAGE_MAP()
498 
499   return handled;
500 }
501 
OnCreateObjectStore(const IndexedDBHostMsg_DatabaseCreateObjectStore_Params & params)502 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
503     const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
504   DCHECK(
505       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
506   IndexedDBConnection* connection =
507       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
508   if (!connection || !connection->IsConnected())
509     return;
510 
511   int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
512   connection->database()->CreateObjectStore(host_transaction_id,
513                                             params.object_store_id,
514                                             params.name,
515                                             params.key_path,
516                                             params.auto_increment);
517   if (parent_->Context()->IsOverQuota(
518           database_url_map_[params.ipc_database_id])) {
519     connection->database()->Abort(
520         host_transaction_id,
521         IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
522   }
523 }
524 
OnDeleteObjectStore(int32 ipc_database_id,int64 transaction_id,int64 object_store_id)525 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
526     int32 ipc_database_id,
527     int64 transaction_id,
528     int64 object_store_id) {
529   DCHECK(
530       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
531   IndexedDBConnection* connection =
532       parent_->GetOrTerminateProcess(&map_, ipc_database_id);
533   if (!connection || !connection->IsConnected())
534     return;
535 
536   connection->database()->DeleteObjectStore(
537       parent_->HostTransactionId(transaction_id), object_store_id);
538 }
539 
OnCreateTransaction(const IndexedDBHostMsg_DatabaseCreateTransaction_Params & params)540 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
541     const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
542   DCHECK(
543       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
544   IndexedDBConnection* connection =
545       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
546   if (!connection || !connection->IsConnected())
547     return;
548 
549   int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
550 
551   if (transaction_database_map_.find(host_transaction_id) !=
552       transaction_database_map_.end()) {
553     DLOG(ERROR) << "Duplicate host_transaction_id.";
554     return;
555   }
556 
557   connection->database()->CreateTransaction(
558       host_transaction_id, connection, params.object_store_ids, params.mode);
559   transaction_database_map_[host_transaction_id] = params.ipc_database_id;
560   parent_->RegisterTransactionId(host_transaction_id,
561                                  database_url_map_[params.ipc_database_id]);
562 }
563 
OnClose(int32 ipc_database_id)564 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
565     int32 ipc_database_id) {
566   DCHECK(
567       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
568   IndexedDBConnection* connection =
569       parent_->GetOrTerminateProcess(&map_, ipc_database_id);
570   if (!connection || !connection->IsConnected())
571     return;
572   connection->Close();
573 }
574 
OnVersionChangeIgnored(int32 ipc_database_id)575 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
576     int32 ipc_database_id) {
577   DCHECK(
578       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
579   IndexedDBConnection* connection =
580       parent_->GetOrTerminateProcess(&map_, ipc_database_id);
581   if (!connection || !connection->IsConnected())
582     return;
583   connection->VersionChangeIgnored();
584 }
585 
OnDestroyed(int32 ipc_object_id)586 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
587     int32 ipc_object_id) {
588   DCHECK(
589       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
590   IndexedDBConnection* connection = map_.Lookup(ipc_object_id);
591   if (connection->IsConnected())
592     connection->Close();
593   parent_->Context()
594       ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
595   database_url_map_.erase(ipc_object_id);
596   parent_->DestroyObject(&map_, ipc_object_id);
597 }
598 
OnGet(const IndexedDBHostMsg_DatabaseGet_Params & params)599 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
600     const IndexedDBHostMsg_DatabaseGet_Params& params) {
601   DCHECK(
602       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
603   IndexedDBConnection* connection =
604       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
605   if (!connection || !connection->IsConnected())
606     return;
607 
608   scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
609       parent_, params.ipc_thread_id, params.ipc_callbacks_id));
610   connection->database()->Get(
611       parent_->HostTransactionId(params.transaction_id),
612       params.object_store_id,
613       params.index_id,
614       make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
615       params.key_only,
616       callbacks);
617 }
618 
OnPutWrapper(const IndexedDBHostMsg_DatabasePut_Params & params)619 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
620     const IndexedDBHostMsg_DatabasePut_Params& params) {
621   std::vector<storage::BlobDataHandle*> handles;
622   for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
623     const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
624     handles.push_back(parent_->blob_storage_context_->context()
625                           ->GetBlobDataFromUUID(info.uuid)
626                           .release());
627   }
628   parent_->indexed_db_context_->TaskRunner()->PostTask(
629       FROM_HERE,
630       base::Bind(
631           &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
632 }
633 
OnPut(const IndexedDBHostMsg_DatabasePut_Params & params,std::vector<storage::BlobDataHandle * > handles)634 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
635     const IndexedDBHostMsg_DatabasePut_Params& params,
636     std::vector<storage::BlobDataHandle*> handles) {
637   DCHECK(
638       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
639 
640   ScopedVector<storage::BlobDataHandle> scoped_handles;
641   scoped_handles.swap(handles);
642 
643   IndexedDBConnection* connection =
644       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
645   if (!connection || !connection->IsConnected())
646     return;
647   scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
648       parent_, params.ipc_thread_id, params.ipc_callbacks_id));
649 
650   int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
651 
652   std::vector<IndexedDBBlobInfo> blob_info(params.blob_or_file_info.size());
653 
654   ChildProcessSecurityPolicyImpl* policy =
655       ChildProcessSecurityPolicyImpl::GetInstance();
656 
657   for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
658     const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
659     if (info.is_file) {
660       base::FilePath path = base::FilePath::FromUTF16Unsafe(info.file_path);
661       if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
662         parent_->BadMessageReceived();
663         return;
664       }
665       blob_info[i] =
666           IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type);
667       if (info.size != static_cast<uint64_t>(-1)) {
668         blob_info[i].set_last_modified(
669             base::Time::FromDoubleT(info.last_modified));
670         blob_info[i].set_size(info.size);
671       }
672     } else {
673       blob_info[i] = IndexedDBBlobInfo(info.uuid, info.mime_type, info.size);
674     }
675   }
676 
677   // TODO(alecflett): Avoid a copy here.
678   IndexedDBValue value;
679   value.bits = params.value;
680   value.blob_info.swap(blob_info);
681   connection->database()->Put(host_transaction_id,
682                               params.object_store_id,
683                               &value,
684                               &scoped_handles,
685                               make_scoped_ptr(new IndexedDBKey(params.key)),
686                               params.put_mode,
687                               callbacks,
688                               params.index_keys);
689   TransactionIDToSizeMap* map =
690       &parent_->database_dispatcher_host_->transaction_size_map_;
691   // Size can't be big enough to overflow because it represents the
692   // actual bytes passed through IPC.
693   (*map)[host_transaction_id] += params.value.size();
694 }
695 
OnSetIndexKeys(const IndexedDBHostMsg_DatabaseSetIndexKeys_Params & params)696 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
697     const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
698   DCHECK(
699       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
700   IndexedDBConnection* connection =
701       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
702   if (!connection || !connection->IsConnected())
703     return;
704 
705   int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
706   connection->database()->SetIndexKeys(
707       host_transaction_id,
708       params.object_store_id,
709       make_scoped_ptr(new IndexedDBKey(params.primary_key)),
710       params.index_keys);
711 }
712 
OnSetIndexesReady(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,const std::vector<int64> & index_ids)713 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
714     int32 ipc_database_id,
715     int64 transaction_id,
716     int64 object_store_id,
717     const std::vector<int64>& index_ids) {
718   DCHECK(
719       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
720   IndexedDBConnection* connection =
721       parent_->GetOrTerminateProcess(&map_, ipc_database_id);
722   if (!connection || !connection->IsConnected())
723     return;
724 
725   connection->database()->SetIndexesReady(
726       parent_->HostTransactionId(transaction_id), object_store_id, index_ids);
727 }
728 
OnOpenCursor(const IndexedDBHostMsg_DatabaseOpenCursor_Params & params)729 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
730     const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
731   DCHECK(
732       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
733   IndexedDBConnection* connection =
734       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
735   if (!connection || !connection->IsConnected())
736     return;
737 
738   scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
739       parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1));
740   connection->database()->OpenCursor(
741       parent_->HostTransactionId(params.transaction_id),
742       params.object_store_id,
743       params.index_id,
744       make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
745       params.direction,
746       params.key_only,
747       params.task_type,
748       callbacks);
749 }
750 
OnCount(const IndexedDBHostMsg_DatabaseCount_Params & params)751 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
752     const IndexedDBHostMsg_DatabaseCount_Params& params) {
753   DCHECK(
754       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
755   IndexedDBConnection* connection =
756       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
757   if (!connection || !connection->IsConnected())
758     return;
759 
760   scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
761       parent_, params.ipc_thread_id, params.ipc_callbacks_id));
762   connection->database()->Count(
763       parent_->HostTransactionId(params.transaction_id),
764       params.object_store_id,
765       params.index_id,
766       make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
767       callbacks);
768 }
769 
OnDeleteRange(const IndexedDBHostMsg_DatabaseDeleteRange_Params & params)770 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
771     const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
772   DCHECK(
773       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
774   IndexedDBConnection* connection =
775       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
776   if (!connection || !connection->IsConnected())
777     return;
778 
779   scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
780       parent_, params.ipc_thread_id, params.ipc_callbacks_id));
781   connection->database()->DeleteRange(
782       parent_->HostTransactionId(params.transaction_id),
783       params.object_store_id,
784       make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
785       callbacks);
786 }
787 
OnClear(int32 ipc_thread_id,int32 ipc_callbacks_id,int32 ipc_database_id,int64 transaction_id,int64 object_store_id)788 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
789     int32 ipc_thread_id,
790     int32 ipc_callbacks_id,
791     int32 ipc_database_id,
792     int64 transaction_id,
793     int64 object_store_id) {
794   DCHECK(
795       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
796   IndexedDBConnection* connection =
797       parent_->GetOrTerminateProcess(&map_, ipc_database_id);
798   if (!connection || !connection->IsConnected())
799     return;
800 
801   scoped_refptr<IndexedDBCallbacks> callbacks(
802       new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id));
803 
804   connection->database()->Clear(
805       parent_->HostTransactionId(transaction_id), object_store_id, callbacks);
806 }
807 
OnAbort(int32 ipc_database_id,int64 transaction_id)808 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
809     int32 ipc_database_id,
810     int64 transaction_id) {
811   DCHECK(
812       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
813   IndexedDBConnection* connection =
814       parent_->GetOrTerminateProcess(&map_, ipc_database_id);
815   if (!connection || !connection->IsConnected())
816     return;
817 
818   connection->database()->Abort(parent_->HostTransactionId(transaction_id));
819 }
820 
OnCommit(int32 ipc_database_id,int64 transaction_id)821 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
822     int32 ipc_database_id,
823     int64 transaction_id) {
824   DCHECK(
825       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
826   IndexedDBConnection* connection =
827       parent_->GetOrTerminateProcess(&map_, ipc_database_id);
828   if (!connection || !connection->IsConnected())
829     return;
830 
831   int64 host_transaction_id = parent_->HostTransactionId(transaction_id);
832   int64 transaction_size = transaction_size_map_[host_transaction_id];
833   if (transaction_size &&
834       parent_->Context()->WouldBeOverQuota(
835           transaction_url_map_[host_transaction_id], transaction_size)) {
836     connection->database()->Abort(
837         host_transaction_id,
838         IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
839     return;
840   }
841 
842   connection->database()->Commit(host_transaction_id);
843 }
844 
OnCreateIndex(const IndexedDBHostMsg_DatabaseCreateIndex_Params & params)845 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
846     const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
847   DCHECK(
848       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
849   IndexedDBConnection* connection =
850       parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
851   if (!connection || !connection->IsConnected())
852     return;
853 
854   int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
855   connection->database()->CreateIndex(host_transaction_id,
856                                       params.object_store_id,
857                                       params.index_id,
858                                       params.name,
859                                       params.key_path,
860                                       params.unique,
861                                       params.multi_entry);
862   if (parent_->Context()->IsOverQuota(
863           database_url_map_[params.ipc_database_id])) {
864     connection->database()->Abort(
865         host_transaction_id,
866         IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
867   }
868 }
869 
OnDeleteIndex(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,int64 index_id)870 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
871     int32 ipc_database_id,
872     int64 transaction_id,
873     int64 object_store_id,
874     int64 index_id) {
875   DCHECK(
876       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
877   IndexedDBConnection* connection =
878       parent_->GetOrTerminateProcess(&map_, ipc_database_id);
879   if (!connection || !connection->IsConnected())
880     return;
881 
882   connection->database()->DeleteIndex(
883       parent_->HostTransactionId(transaction_id), object_store_id, index_id);
884 }
885 
886 //////////////////////////////////////////////////////////////////////
887 // IndexedDBDispatcherHost::CursorDispatcherHost
888 //
889 
CursorDispatcherHost(IndexedDBDispatcherHost * parent)890 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
891     IndexedDBDispatcherHost* parent)
892     : parent_(parent) {
893   map_.set_check_on_null_data(true);
894 }
895 
~CursorDispatcherHost()896 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
897 
OnMessageReceived(const IPC::Message & message)898 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
899     const IPC::Message& message) {
900   bool handled = true;
901   IPC_BEGIN_MESSAGE_MAP(
902       IndexedDBDispatcherHost::CursorDispatcherHost, message)
903     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance)
904     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
905     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch)
906     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset)
907     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
908     IPC_MESSAGE_UNHANDLED(handled = false)
909   IPC_END_MESSAGE_MAP()
910 
911   DCHECK(
912       !handled ||
913       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
914 
915   return handled;
916 }
917 
OnAdvance(int32 ipc_cursor_id,int32 ipc_thread_id,int32 ipc_callbacks_id,uint32 count)918 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
919     int32 ipc_cursor_id,
920     int32 ipc_thread_id,
921     int32 ipc_callbacks_id,
922     uint32 count) {
923   DCHECK(
924       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
925   IndexedDBCursor* idb_cursor =
926       parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
927   if (!idb_cursor)
928     return;
929 
930   idb_cursor->Advance(
931       count,
932       new IndexedDBCallbacks(
933           parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
934 }
935 
OnContinue(int32 ipc_cursor_id,int32 ipc_thread_id,int32 ipc_callbacks_id,const IndexedDBKey & key,const IndexedDBKey & primary_key)936 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
937     int32 ipc_cursor_id,
938     int32 ipc_thread_id,
939     int32 ipc_callbacks_id,
940     const IndexedDBKey& key,
941     const IndexedDBKey& primary_key) {
942   DCHECK(
943       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
944   IndexedDBCursor* idb_cursor =
945       parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
946   if (!idb_cursor)
947     return;
948 
949   idb_cursor->Continue(
950       key.IsValid() ? make_scoped_ptr(new IndexedDBKey(key))
951                     : scoped_ptr<IndexedDBKey>(),
952       primary_key.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key))
953                             : scoped_ptr<IndexedDBKey>(),
954       new IndexedDBCallbacks(
955           parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
956 }
957 
OnPrefetch(int32 ipc_cursor_id,int32 ipc_thread_id,int32 ipc_callbacks_id,int n)958 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
959     int32 ipc_cursor_id,
960     int32 ipc_thread_id,
961     int32 ipc_callbacks_id,
962     int n) {
963   DCHECK(
964       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
965   IndexedDBCursor* idb_cursor =
966       parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
967   if (!idb_cursor)
968     return;
969 
970   idb_cursor->PrefetchContinue(
971       n,
972       new IndexedDBCallbacks(
973           parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
974 }
975 
OnPrefetchReset(int32 ipc_cursor_id,int used_prefetches,int unused_prefetches)976 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
977     int32 ipc_cursor_id,
978     int used_prefetches,
979     int unused_prefetches) {
980   DCHECK(
981       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
982   IndexedDBCursor* idb_cursor =
983       parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
984   if (!idb_cursor)
985     return;
986 
987   leveldb::Status s =
988       idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
989   // TODO(cmumford): Handle this error (crbug.com/363397)
990   if (!s.ok())
991     DLOG(ERROR) << "Unable to reset prefetch";
992 }
993 
OnDestroyed(int32 ipc_object_id)994 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
995     int32 ipc_object_id) {
996   DCHECK(
997       parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
998   parent_->DestroyObject(&map_, ipc_object_id);
999 }
1000 
1001 }  // namespace content
1002