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 "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
30 #include "url/gurl.h"
31 #include "webkit/browser/blob/blob_storage_context.h"
32 #include "webkit/browser/database/database_util.h"
33 #include "webkit/common/database/database_identifier.h"
34
35 using webkit_database::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_);
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_);
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<webkit_blob::BlobDataHandle> & blob_data_handle)212 void IndexedDBDispatcherHost::HoldBlobDataHandle(
213 const std::string& uuid,
214 scoped_ptr<webkit_blob::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 webkit_database::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::FilePath indexed_db_path = indexed_db_context_->data_path();
295
296 GURL origin_url =
297 webkit_database::GetOriginFromIdentifier(params.database_identifier);
298
299 int64 host_transaction_id = HostTransactionId(params.transaction_id);
300
301 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore
302 // created) if this origin is already over quota.
303 scoped_refptr<IndexedDBCallbacks> callbacks =
304 new IndexedDBCallbacks(this,
305 params.ipc_thread_id,
306 params.ipc_callbacks_id,
307 params.ipc_database_callbacks_id,
308 host_transaction_id,
309 origin_url);
310 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
311 new IndexedDBDatabaseCallbacks(
312 this, params.ipc_thread_id, params.ipc_database_callbacks_id);
313 IndexedDBPendingConnection connection(callbacks,
314 database_callbacks,
315 ipc_process_id_,
316 host_transaction_id,
317 params.version);
318 DCHECK(request_context_);
319 Context()->GetIDBFactory()->Open(
320 params.name, connection, request_context_, origin_url, indexed_db_path);
321 }
322
OnIDBFactoryDeleteDatabase(const IndexedDBHostMsg_FactoryDeleteDatabase_Params & params)323 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
324 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
325 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
326 GURL origin_url =
327 webkit_database::GetOriginFromIdentifier(params.database_identifier);
328 base::FilePath indexed_db_path = indexed_db_context_->data_path();
329 DCHECK(request_context_);
330 Context()->GetIDBFactory()->DeleteDatabase(
331 params.name,
332 request_context_,
333 new IndexedDBCallbacks(
334 this, params.ipc_thread_id, params.ipc_callbacks_id),
335 origin_url,
336 indexed_db_path);
337 }
338
339 // OnPutHelper exists only to allow us to hop threads while holding a reference
340 // to the IndexedDBDispatcherHost.
OnPutHelper(const IndexedDBHostMsg_DatabasePut_Params & params,std::vector<webkit_blob::BlobDataHandle * > handles)341 void IndexedDBDispatcherHost::OnPutHelper(
342 const IndexedDBHostMsg_DatabasePut_Params& params,
343 std::vector<webkit_blob::BlobDataHandle*> handles) {
344 database_dispatcher_host_->OnPut(params, handles);
345 }
346
OnAckReceivedBlobs(const std::vector<std::string> & uuids)347 void IndexedDBDispatcherHost::OnAckReceivedBlobs(
348 const std::vector<std::string>& uuids) {
349 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
350 std::vector<std::string>::const_iterator iter;
351 for (iter = uuids.begin(); iter != uuids.end(); ++iter)
352 DropBlobDataHandle(*iter);
353 }
354
FinishTransaction(int64 host_transaction_id,bool committed)355 void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
356 bool committed) {
357 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
358 if (!database_dispatcher_host_)
359 return;
360 TransactionIDToURLMap& transaction_url_map =
361 database_dispatcher_host_->transaction_url_map_;
362 TransactionIDToSizeMap& transaction_size_map =
363 database_dispatcher_host_->transaction_size_map_;
364 TransactionIDToDatabaseIDMap& transaction_database_map =
365 database_dispatcher_host_->transaction_database_map_;
366 if (committed)
367 Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
368 transaction_url_map.erase(host_transaction_id);
369 transaction_size_map.erase(host_transaction_id);
370 transaction_database_map.erase(host_transaction_id);
371 }
372
373 //////////////////////////////////////////////////////////////////////
374 // Helper templates.
375 //
376
377 template <typename ObjectType>
GetOrTerminateProcess(IDMap<ObjectType,IDMapOwnPointer> * map,int32 ipc_return_object_id)378 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
379 IDMap<ObjectType, IDMapOwnPointer>* map,
380 int32 ipc_return_object_id) {
381 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
382 ObjectType* return_object = map->Lookup(ipc_return_object_id);
383 if (!return_object) {
384 NOTREACHED() << "Uh oh, couldn't find object with id "
385 << ipc_return_object_id;
386 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
387 BadMessageReceived();
388 }
389 return return_object;
390 }
391
392 template <typename ObjectType>
GetOrTerminateProcess(RefIDMap<ObjectType> * map,int32 ipc_return_object_id)393 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
394 RefIDMap<ObjectType>* map,
395 int32 ipc_return_object_id) {
396 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
397 ObjectType* return_object = map->Lookup(ipc_return_object_id);
398 if (!return_object) {
399 NOTREACHED() << "Uh oh, couldn't find object with id "
400 << ipc_return_object_id;
401 RecordAction(base::UserMetricsAction("BadMessageTerminate_IDBMF"));
402 BadMessageReceived();
403 }
404 return return_object;
405 }
406
407 template <typename MapType>
DestroyObject(MapType * map,int32 ipc_object_id)408 void IndexedDBDispatcherHost::DestroyObject(MapType* map, int32 ipc_object_id) {
409 GetOrTerminateProcess(map, ipc_object_id);
410 map->Remove(ipc_object_id);
411 }
412
413 //////////////////////////////////////////////////////////////////////
414 // IndexedDBDispatcherHost::DatabaseDispatcherHost
415 //
416
DatabaseDispatcherHost(IndexedDBDispatcherHost * parent)417 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
418 IndexedDBDispatcherHost* parent)
419 : parent_(parent) {
420 map_.set_check_on_null_data(true);
421 }
422
~DatabaseDispatcherHost()423 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
424 // TODO(alecflett): uncomment these when we find the source of these leaks.
425 // DCHECK(transaction_size_map_.empty());
426 // DCHECK(transaction_url_map_.empty());
427 }
428
CloseAll()429 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
430 DCHECK(
431 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
432 // Abort outstanding transactions started by connections in the associated
433 // front-end to unblock later transactions. This should only occur on unclean
434 // (crash) or abrupt (process-kill) shutdowns.
435 for (TransactionIDToDatabaseIDMap::iterator iter =
436 transaction_database_map_.begin();
437 iter != transaction_database_map_.end();) {
438 int64 transaction_id = iter->first;
439 int32 ipc_database_id = iter->second;
440 ++iter;
441 IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
442 if (connection && connection->IsConnected()) {
443 connection->database()->Abort(
444 transaction_id,
445 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError));
446 }
447 }
448 DCHECK(transaction_database_map_.empty());
449
450 for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin();
451 iter != database_url_map_.end();
452 iter++) {
453 IndexedDBConnection* connection = map_.Lookup(iter->first);
454 if (connection && connection->IsConnected()) {
455 connection->Close();
456 parent_->Context()->ConnectionClosed(iter->second, connection);
457 }
458 }
459 }
460
OnMessageReceived(const IPC::Message & message)461 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
462 const IPC::Message& message) {
463
464 DCHECK(
465 (message.type() == IndexedDBHostMsg_DatabasePut::ID) ||
466 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
467
468 bool handled = true;
469 IPC_BEGIN_MESSAGE_MAP(
470 IndexedDBDispatcherHost::DatabaseDispatcherHost, message)
471 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
472 OnCreateObjectStore)
473 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
474 OnDeleteObjectStore)
475 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
476 OnCreateTransaction)
477 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
478 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
479 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
480 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
481 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
482 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
483 OnSetIndexesReady)
484 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor)
485 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount)
486 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange)
487 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear)
488 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex)
489 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex)
490 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort)
491 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit)
492 IPC_MESSAGE_UNHANDLED(handled = false)
493 IPC_END_MESSAGE_MAP()
494
495 return handled;
496 }
497
OnCreateObjectStore(const IndexedDBHostMsg_DatabaseCreateObjectStore_Params & params)498 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
499 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
500 DCHECK(
501 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
502 IndexedDBConnection* connection =
503 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
504 if (!connection || !connection->IsConnected())
505 return;
506
507 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
508 connection->database()->CreateObjectStore(host_transaction_id,
509 params.object_store_id,
510 params.name,
511 params.key_path,
512 params.auto_increment);
513 if (parent_->Context()->IsOverQuota(
514 database_url_map_[params.ipc_database_id])) {
515 connection->database()->Abort(
516 host_transaction_id,
517 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
518 }
519 }
520
OnDeleteObjectStore(int32 ipc_database_id,int64 transaction_id,int64 object_store_id)521 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
522 int32 ipc_database_id,
523 int64 transaction_id,
524 int64 object_store_id) {
525 DCHECK(
526 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
527 IndexedDBConnection* connection =
528 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
529 if (!connection || !connection->IsConnected())
530 return;
531
532 connection->database()->DeleteObjectStore(
533 parent_->HostTransactionId(transaction_id), object_store_id);
534 }
535
OnCreateTransaction(const IndexedDBHostMsg_DatabaseCreateTransaction_Params & params)536 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
537 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
538 DCHECK(
539 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
540 IndexedDBConnection* connection =
541 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
542 if (!connection || !connection->IsConnected())
543 return;
544
545 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
546
547 if (transaction_database_map_.find(host_transaction_id) !=
548 transaction_database_map_.end()) {
549 DLOG(ERROR) << "Duplicate host_transaction_id.";
550 return;
551 }
552
553 connection->database()->CreateTransaction(
554 host_transaction_id, connection, params.object_store_ids, params.mode);
555 transaction_database_map_[host_transaction_id] = params.ipc_database_id;
556 parent_->RegisterTransactionId(host_transaction_id,
557 database_url_map_[params.ipc_database_id]);
558 }
559
OnClose(int32 ipc_database_id)560 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
561 int32 ipc_database_id) {
562 DCHECK(
563 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
564 IndexedDBConnection* connection =
565 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
566 if (!connection || !connection->IsConnected())
567 return;
568 connection->Close();
569 }
570
OnDestroyed(int32 ipc_object_id)571 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
572 int32 ipc_object_id) {
573 DCHECK(
574 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
575 IndexedDBConnection* connection = map_.Lookup(ipc_object_id);
576 if (connection->IsConnected())
577 connection->Close();
578 parent_->Context()
579 ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
580 database_url_map_.erase(ipc_object_id);
581 parent_->DestroyObject(&map_, ipc_object_id);
582 }
583
OnGet(const IndexedDBHostMsg_DatabaseGet_Params & params)584 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
585 const IndexedDBHostMsg_DatabaseGet_Params& params) {
586 DCHECK(
587 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
588 IndexedDBConnection* connection =
589 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
590 if (!connection || !connection->IsConnected())
591 return;
592
593 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
594 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
595 connection->database()->Get(
596 parent_->HostTransactionId(params.transaction_id),
597 params.object_store_id,
598 params.index_id,
599 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
600 params.key_only,
601 callbacks);
602 }
603
OnPutWrapper(const IndexedDBHostMsg_DatabasePut_Params & params)604 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
605 const IndexedDBHostMsg_DatabasePut_Params& params) {
606 std::vector<webkit_blob::BlobDataHandle*> handles;
607 for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
608 const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
609 handles.push_back(parent_->blob_storage_context_->context()
610 ->GetBlobDataFromUUID(info.uuid)
611 .release());
612 }
613 parent_->indexed_db_context_->TaskRunner()->PostTask(
614 FROM_HERE,
615 base::Bind(
616 &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
617 }
618
OnPut(const IndexedDBHostMsg_DatabasePut_Params & params,std::vector<webkit_blob::BlobDataHandle * > handles)619 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
620 const IndexedDBHostMsg_DatabasePut_Params& params,
621 std::vector<webkit_blob::BlobDataHandle*> handles) {
622
623 DCHECK(
624 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
625
626 ScopedVector<webkit_blob::BlobDataHandle> scoped_handles;
627 scoped_handles.swap(handles);
628
629 IndexedDBConnection* connection =
630 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
631 if (!connection || !connection->IsConnected())
632 return;
633 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
634 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
635
636 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
637
638 std::vector<IndexedDBBlobInfo> blob_info(params.blob_or_file_info.size());
639
640 ChildProcessSecurityPolicyImpl* policy =
641 ChildProcessSecurityPolicyImpl::GetInstance();
642
643 for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
644 const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
645 if (info.is_file) {
646 base::FilePath path = base::FilePath::FromUTF16Unsafe(info.file_path);
647 if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
648 parent_->BadMessageReceived();
649 return;
650 }
651 blob_info[i] =
652 IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type);
653 if (info.size != static_cast<uint64_t>(-1)) {
654 blob_info[i].set_last_modified(
655 base::Time::FromDoubleT(info.last_modified));
656 blob_info[i].set_size(info.size);
657 }
658 } else {
659 blob_info[i] = IndexedDBBlobInfo(info.uuid, info.mime_type, info.size);
660 }
661 }
662
663 // TODO(alecflett): Avoid a copy here.
664 IndexedDBValue value;
665 value.bits = params.value;
666 value.blob_info.swap(blob_info);
667 connection->database()->Put(
668 host_transaction_id,
669 params.object_store_id,
670 &value,
671 &scoped_handles,
672 make_scoped_ptr(new IndexedDBKey(params.key)),
673 static_cast<IndexedDBDatabase::PutMode>(params.put_mode),
674 callbacks,
675 params.index_keys);
676 TransactionIDToSizeMap* map =
677 &parent_->database_dispatcher_host_->transaction_size_map_;
678 // Size can't be big enough to overflow because it represents the
679 // actual bytes passed through IPC.
680 (*map)[host_transaction_id] += params.value.size();
681 }
682
OnSetIndexKeys(const IndexedDBHostMsg_DatabaseSetIndexKeys_Params & params)683 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
684 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
685 DCHECK(
686 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
687 IndexedDBConnection* connection =
688 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
689 if (!connection || !connection->IsConnected())
690 return;
691
692 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
693 connection->database()->SetIndexKeys(
694 host_transaction_id,
695 params.object_store_id,
696 make_scoped_ptr(new IndexedDBKey(params.primary_key)),
697 params.index_keys);
698 }
699
OnSetIndexesReady(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,const std::vector<int64> & index_ids)700 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
701 int32 ipc_database_id,
702 int64 transaction_id,
703 int64 object_store_id,
704 const std::vector<int64>& index_ids) {
705 DCHECK(
706 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
707 IndexedDBConnection* connection =
708 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
709 if (!connection || !connection->IsConnected())
710 return;
711
712 connection->database()->SetIndexesReady(
713 parent_->HostTransactionId(transaction_id), object_store_id, index_ids);
714 }
715
OnOpenCursor(const IndexedDBHostMsg_DatabaseOpenCursor_Params & params)716 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
717 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
718 DCHECK(
719 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
720 IndexedDBConnection* connection =
721 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
722 if (!connection || !connection->IsConnected())
723 return;
724
725 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
726 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1));
727 connection->database()->OpenCursor(
728 parent_->HostTransactionId(params.transaction_id),
729 params.object_store_id,
730 params.index_id,
731 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
732 static_cast<indexed_db::CursorDirection>(params.direction),
733 params.key_only,
734 static_cast<IndexedDBDatabase::TaskType>(params.task_type),
735 callbacks);
736 }
737
OnCount(const IndexedDBHostMsg_DatabaseCount_Params & params)738 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
739 const IndexedDBHostMsg_DatabaseCount_Params& params) {
740 DCHECK(
741 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
742 IndexedDBConnection* connection =
743 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
744 if (!connection || !connection->IsConnected())
745 return;
746
747 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
748 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
749 connection->database()->Count(
750 parent_->HostTransactionId(params.transaction_id),
751 params.object_store_id,
752 params.index_id,
753 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
754 callbacks);
755 }
756
OnDeleteRange(const IndexedDBHostMsg_DatabaseDeleteRange_Params & params)757 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
758 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
759 DCHECK(
760 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
761 IndexedDBConnection* connection =
762 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
763 if (!connection || !connection->IsConnected())
764 return;
765
766 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
767 parent_, params.ipc_thread_id, params.ipc_callbacks_id));
768 connection->database()->DeleteRange(
769 parent_->HostTransactionId(params.transaction_id),
770 params.object_store_id,
771 make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
772 callbacks);
773 }
774
OnClear(int32 ipc_thread_id,int32 ipc_callbacks_id,int32 ipc_database_id,int64 transaction_id,int64 object_store_id)775 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
776 int32 ipc_thread_id,
777 int32 ipc_callbacks_id,
778 int32 ipc_database_id,
779 int64 transaction_id,
780 int64 object_store_id) {
781 DCHECK(
782 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
783 IndexedDBConnection* connection =
784 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
785 if (!connection || !connection->IsConnected())
786 return;
787
788 scoped_refptr<IndexedDBCallbacks> callbacks(
789 new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id));
790
791 connection->database()->Clear(
792 parent_->HostTransactionId(transaction_id), object_store_id, callbacks);
793 }
794
OnAbort(int32 ipc_database_id,int64 transaction_id)795 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
796 int32 ipc_database_id,
797 int64 transaction_id) {
798 DCHECK(
799 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
800 IndexedDBConnection* connection =
801 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
802 if (!connection || !connection->IsConnected())
803 return;
804
805 connection->database()->Abort(parent_->HostTransactionId(transaction_id));
806 }
807
OnCommit(int32 ipc_database_id,int64 transaction_id)808 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
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 int64 host_transaction_id = parent_->HostTransactionId(transaction_id);
819 int64 transaction_size = transaction_size_map_[host_transaction_id];
820 if (transaction_size &&
821 parent_->Context()->WouldBeOverQuota(
822 transaction_url_map_[host_transaction_id], transaction_size)) {
823 connection->database()->Abort(
824 host_transaction_id,
825 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
826 return;
827 }
828
829 connection->database()->Commit(host_transaction_id);
830 }
831
OnCreateIndex(const IndexedDBHostMsg_DatabaseCreateIndex_Params & params)832 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
833 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
834 DCHECK(
835 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
836 IndexedDBConnection* connection =
837 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
838 if (!connection || !connection->IsConnected())
839 return;
840
841 int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
842 connection->database()->CreateIndex(host_transaction_id,
843 params.object_store_id,
844 params.index_id,
845 params.name,
846 params.key_path,
847 params.unique,
848 params.multi_entry);
849 if (parent_->Context()->IsOverQuota(
850 database_url_map_[params.ipc_database_id])) {
851 connection->database()->Abort(
852 host_transaction_id,
853 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
854 }
855 }
856
OnDeleteIndex(int32 ipc_database_id,int64 transaction_id,int64 object_store_id,int64 index_id)857 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
858 int32 ipc_database_id,
859 int64 transaction_id,
860 int64 object_store_id,
861 int64 index_id) {
862 DCHECK(
863 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
864 IndexedDBConnection* connection =
865 parent_->GetOrTerminateProcess(&map_, ipc_database_id);
866 if (!connection || !connection->IsConnected())
867 return;
868
869 connection->database()->DeleteIndex(
870 parent_->HostTransactionId(transaction_id), object_store_id, index_id);
871 }
872
873 //////////////////////////////////////////////////////////////////////
874 // IndexedDBDispatcherHost::CursorDispatcherHost
875 //
876
CursorDispatcherHost(IndexedDBDispatcherHost * parent)877 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
878 IndexedDBDispatcherHost* parent)
879 : parent_(parent) {
880 map_.set_check_on_null_data(true);
881 }
882
~CursorDispatcherHost()883 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {}
884
OnMessageReceived(const IPC::Message & message)885 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
886 const IPC::Message& message) {
887 bool handled = true;
888 IPC_BEGIN_MESSAGE_MAP(
889 IndexedDBDispatcherHost::CursorDispatcherHost, message)
890 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance)
891 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
892 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch)
893 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset)
894 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
895 IPC_MESSAGE_UNHANDLED(handled = false)
896 IPC_END_MESSAGE_MAP()
897
898 DCHECK(
899 !handled ||
900 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
901
902 return handled;
903 }
904
OnAdvance(int32 ipc_cursor_id,int32 ipc_thread_id,int32 ipc_callbacks_id,uint32 count)905 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
906 int32 ipc_cursor_id,
907 int32 ipc_thread_id,
908 int32 ipc_callbacks_id,
909 uint32 count) {
910 DCHECK(
911 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
912 IndexedDBCursor* idb_cursor =
913 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
914 if (!idb_cursor)
915 return;
916
917 idb_cursor->Advance(
918 count,
919 new IndexedDBCallbacks(
920 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
921 }
922
OnContinue(int32 ipc_cursor_id,int32 ipc_thread_id,int32 ipc_callbacks_id,const IndexedDBKey & key,const IndexedDBKey & primary_key)923 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
924 int32 ipc_cursor_id,
925 int32 ipc_thread_id,
926 int32 ipc_callbacks_id,
927 const IndexedDBKey& key,
928 const IndexedDBKey& primary_key) {
929 DCHECK(
930 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
931 IndexedDBCursor* idb_cursor =
932 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
933 if (!idb_cursor)
934 return;
935
936 idb_cursor->Continue(
937 key.IsValid() ? make_scoped_ptr(new IndexedDBKey(key))
938 : scoped_ptr<IndexedDBKey>(),
939 primary_key.IsValid() ? make_scoped_ptr(new IndexedDBKey(primary_key))
940 : scoped_ptr<IndexedDBKey>(),
941 new IndexedDBCallbacks(
942 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
943 }
944
OnPrefetch(int32 ipc_cursor_id,int32 ipc_thread_id,int32 ipc_callbacks_id,int n)945 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
946 int32 ipc_cursor_id,
947 int32 ipc_thread_id,
948 int32 ipc_callbacks_id,
949 int n) {
950 DCHECK(
951 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
952 IndexedDBCursor* idb_cursor =
953 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
954 if (!idb_cursor)
955 return;
956
957 idb_cursor->PrefetchContinue(
958 n,
959 new IndexedDBCallbacks(
960 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id));
961 }
962
OnPrefetchReset(int32 ipc_cursor_id,int used_prefetches,int unused_prefetches)963 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
964 int32 ipc_cursor_id,
965 int used_prefetches,
966 int unused_prefetches) {
967 DCHECK(
968 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
969 IndexedDBCursor* idb_cursor =
970 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
971 if (!idb_cursor)
972 return;
973
974 leveldb::Status s =
975 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches);
976 // TODO(cmumford): Handle this error (crbug.com/363397)
977 if (!s.ok())
978 DLOG(ERROR) << "Unable to reset prefetch";
979 }
980
OnDestroyed(int32 ipc_object_id)981 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
982 int32 ipc_object_id) {
983 DCHECK(
984 parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
985 parent_->DestroyObject(&map_, ipc_object_id);
986 }
987
988 } // namespace content
989