OLD | NEW |
| (Empty) |
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 <stddef.h> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/command_line.h" | |
11 #include "base/files/file_path.h" | |
12 #include "base/guid.h" | |
13 #include "base/memory/ptr_util.h" | |
14 #include "base/memory/scoped_vector.h" | |
15 #include "base/process/process.h" | |
16 #include "base/stl_util.h" | |
17 #include "base/strings/utf_string_conversions.h" | |
18 #include "content/browser/bad_message.h" | |
19 #include "content/browser/child_process_security_policy_impl.h" | |
20 #include "content/browser/indexed_db/indexed_db_callbacks.h" | |
21 #include "content/browser/indexed_db/indexed_db_connection.h" | |
22 #include "content/browser/indexed_db/indexed_db_context_impl.h" | |
23 #include "content/browser/indexed_db/indexed_db_cursor.h" | |
24 #include "content/browser/indexed_db/indexed_db_database_callbacks.h" | |
25 #include "content/browser/indexed_db/indexed_db_metadata.h" | |
26 #include "content/browser/indexed_db/indexed_db_observation.h" | |
27 #include "content/browser/indexed_db/indexed_db_observer_changes.h" | |
28 #include "content/browser/indexed_db/indexed_db_pending_connection.h" | |
29 #include "content/browser/indexed_db/indexed_db_value.h" | |
30 #include "content/browser/renderer_host/render_message_filter.h" | |
31 #include "content/common/indexed_db/indexed_db_messages.h" | |
32 #include "content/public/browser/browser_thread.h" | |
33 #include "content/public/browser/user_metrics.h" | |
34 #include "content/public/common/content_switches.h" | |
35 #include "content/public/common/result_codes.h" | |
36 #include "storage/browser/blob/blob_data_builder.h" | |
37 #include "storage/browser/blob/blob_storage_context.h" | |
38 #include "storage/browser/database/database_util.h" | |
39 #include "storage/browser/quota/quota_manager_proxy.h" | |
40 #include "storage/common/database/database_identifier.h" | |
41 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseExc
eption.h" | |
42 #include "url/origin.h" | |
43 | |
44 using storage::DatabaseUtil; | |
45 using blink::WebIDBKey; | |
46 | |
47 namespace content { | |
48 | |
49 namespace { | |
50 | |
51 bool IsValidOrigin(const url::Origin& origin) { | |
52 return !origin.unique(); | |
53 } | |
54 | |
55 } // namespace | |
56 | |
57 IndexedDBDispatcherHost::IndexedDBDispatcherHost( | |
58 int ipc_process_id, | |
59 net::URLRequestContextGetter* request_context_getter, | |
60 IndexedDBContextImpl* indexed_db_context, | |
61 ChromeBlobStorageContext* blob_storage_context) | |
62 : BrowserMessageFilter(IndexedDBMsgStart), | |
63 request_context_getter_(request_context_getter), | |
64 indexed_db_context_(indexed_db_context), | |
65 blob_storage_context_(blob_storage_context), | |
66 database_dispatcher_host_(base::MakeUnique<DatabaseDispatcherHost>(this)), | |
67 cursor_dispatcher_host_(base::MakeUnique<CursorDispatcherHost>(this)), | |
68 ipc_process_id_(ipc_process_id) { | |
69 DCHECK(indexed_db_context_.get()); | |
70 } | |
71 | |
72 IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {} | |
73 | |
74 void IndexedDBDispatcherHost::OnChannelClosing() { | |
75 bool success = indexed_db_context_->TaskRunner()->PostTask( | |
76 FROM_HERE, | |
77 base::Bind(&IndexedDBDispatcherHost::ResetDispatcherHosts, this)); | |
78 | |
79 if (!success) | |
80 ResetDispatcherHosts(); | |
81 } | |
82 | |
83 void IndexedDBDispatcherHost::OnDestruct() const { | |
84 // The last reference to the dispatcher may be a posted task, which would | |
85 // be destructed on the IndexedDB thread. Without this override, that would | |
86 // take the dispatcher with it. Since the dispatcher may be keeping the | |
87 // IndexedDBContext alive, it might be destructed to on its own thread, | |
88 // which is not supported. Ensure destruction runs on the IO thread instead. | |
89 BrowserThread::DeleteOnIOThread::Destruct(this); | |
90 } | |
91 | |
92 void IndexedDBDispatcherHost::ResetDispatcherHosts() { | |
93 // It is important that the various *_dispatcher_host_ members are reset | |
94 // on the IndexedDB thread, since there might be incoming messages on that | |
95 // thread, and we must not reset the dispatcher hosts until after those | |
96 // messages are processed. | |
97 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); | |
98 | |
99 // Note that we explicitly separate CloseAll() from destruction of the | |
100 // DatabaseDispatcherHost, since CloseAll() can invoke callbacks which need to | |
101 // be dispatched through database_dispatcher_host_. | |
102 database_dispatcher_host_->CloseAll(); | |
103 database_dispatcher_host_.reset(); | |
104 cursor_dispatcher_host_.reset(); | |
105 } | |
106 | |
107 base::TaskRunner* IndexedDBDispatcherHost::OverrideTaskRunnerForMessage( | |
108 const IPC::Message& message) { | |
109 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart) | |
110 return NULL; | |
111 | |
112 switch (message.type()) { | |
113 case IndexedDBHostMsg_DatabasePut::ID: | |
114 case IndexedDBHostMsg_AckReceivedBlobs::ID: | |
115 return NULL; | |
116 default: | |
117 return indexed_db_context_->TaskRunner(); | |
118 } | |
119 } | |
120 | |
121 bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) { | |
122 if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart) | |
123 return false; | |
124 | |
125 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread() || | |
126 (message.type() == IndexedDBHostMsg_DatabasePut::ID || | |
127 message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID)); | |
128 | |
129 bool handled = database_dispatcher_host_->OnMessageReceived(message) || | |
130 cursor_dispatcher_host_->OnMessageReceived(message); | |
131 | |
132 if (!handled) { | |
133 handled = true; | |
134 IPC_BEGIN_MESSAGE_MAP(IndexedDBDispatcherHost, message) | |
135 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryGetDatabaseNames, | |
136 OnIDBFactoryGetDatabaseNames) | |
137 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen) | |
138 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase, | |
139 OnIDBFactoryDeleteDatabase) | |
140 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_AckReceivedBlobs, OnAckReceivedBlobs) | |
141 IPC_MESSAGE_UNHANDLED(handled = false) | |
142 IPC_END_MESSAGE_MAP() | |
143 } | |
144 return handled; | |
145 } | |
146 | |
147 int32_t IndexedDBDispatcherHost::Add(IndexedDBCursor* cursor) { | |
148 if (!cursor_dispatcher_host_) { | |
149 return 0; | |
150 } | |
151 return cursor_dispatcher_host_->map_.Add(cursor); | |
152 } | |
153 | |
154 int32_t IndexedDBDispatcherHost::Add(IndexedDBConnection* connection, | |
155 int32_t ipc_thread_id, | |
156 const url::Origin& origin) { | |
157 if (!database_dispatcher_host_) { | |
158 connection->Close(); | |
159 delete connection; | |
160 return -1; | |
161 } | |
162 int32_t ipc_database_id = database_dispatcher_host_->map_.Add(connection); | |
163 connection->set_id(ipc_database_id); | |
164 context()->ConnectionOpened(origin, connection); | |
165 database_dispatcher_host_->database_origin_map_[ipc_database_id] = origin; | |
166 return ipc_database_id; | |
167 } | |
168 | |
169 void IndexedDBDispatcherHost::RegisterTransactionId(int64_t host_transaction_id, | |
170 const url::Origin& origin) { | |
171 if (!database_dispatcher_host_) | |
172 return; | |
173 database_dispatcher_host_->transaction_size_map_[host_transaction_id] = 0; | |
174 database_dispatcher_host_->transaction_origin_map_[host_transaction_id] = | |
175 origin; | |
176 } | |
177 | |
178 int64_t IndexedDBDispatcherHost::HostTransactionId(int64_t transaction_id) { | |
179 // Inject the renderer process id into the transaction id, to | |
180 // uniquely identify this transaction, and effectively bind it to | |
181 // the renderer that initiated it. The lower 32 bits of | |
182 // transaction_id are guaranteed to be unique within that renderer. | |
183 base::ProcessId pid = peer_pid(); | |
184 DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits"; | |
185 static_assert(sizeof(base::ProcessId) <= sizeof(int32_t), | |
186 "Process ID must fit in 32 bits"); | |
187 | |
188 return transaction_id | (static_cast<uint64_t>(pid) << 32); | |
189 } | |
190 | |
191 int64_t IndexedDBDispatcherHost::RendererTransactionId( | |
192 int64_t host_transaction_id) { | |
193 DCHECK(host_transaction_id >> 32 == peer_pid()) | |
194 << "Invalid renderer target for transaction id"; | |
195 return host_transaction_id & 0xffffffff; | |
196 } | |
197 | |
198 // static | |
199 uint32_t IndexedDBDispatcherHost::TransactionIdToRendererTransactionId( | |
200 int64_t host_transaction_id) { | |
201 return host_transaction_id & 0xffffffff; | |
202 } | |
203 | |
204 // static | |
205 uint32_t IndexedDBDispatcherHost::TransactionIdToProcessId( | |
206 int64_t host_transaction_id) { | |
207 return (host_transaction_id >> 32) & 0xffffffff; | |
208 } | |
209 | |
210 std::string IndexedDBDispatcherHost::HoldBlobData( | |
211 const IndexedDBBlobInfo& blob_info) { | |
212 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
213 std::string uuid = blob_info.uuid(); | |
214 storage::BlobStorageContext* context = blob_storage_context_->context(); | |
215 std::unique_ptr<storage::BlobDataHandle> blob_data_handle; | |
216 if (uuid.empty()) { | |
217 uuid = base::GenerateGUID(); | |
218 storage::BlobDataBuilder blob_data_builder(uuid); | |
219 blob_data_builder.set_content_type(base::UTF16ToUTF8(blob_info.type())); | |
220 blob_data_builder.AppendFile(blob_info.file_path(), 0, blob_info.size(), | |
221 blob_info.last_modified()); | |
222 blob_data_handle = context->AddFinishedBlob(&blob_data_builder); | |
223 } else { | |
224 auto iter = blob_data_handle_map_.find(uuid); | |
225 if (iter != blob_data_handle_map_.end()) { | |
226 iter->second.second += 1; | |
227 return uuid; | |
228 } | |
229 blob_data_handle = context->GetBlobDataFromUUID(uuid); | |
230 } | |
231 | |
232 DCHECK(!base::ContainsKey(blob_data_handle_map_, uuid)); | |
233 blob_data_handle_map_[uuid] = std::make_pair(std::move(blob_data_handle), 1); | |
234 return uuid; | |
235 } | |
236 | |
237 void IndexedDBDispatcherHost::DropBlobData(const std::string& uuid) { | |
238 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
239 const auto& iter = blob_data_handle_map_.find(uuid); | |
240 if (iter == blob_data_handle_map_.end()) { | |
241 DLOG(FATAL) << "Failed to find blob UUID in map:" << uuid; | |
242 return; | |
243 } | |
244 | |
245 DCHECK_GE(iter->second.second, 1); | |
246 if (iter->second.second == 1) | |
247 blob_data_handle_map_.erase(iter); | |
248 else | |
249 --iter->second.second; | |
250 } | |
251 | |
252 IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId( | |
253 int32_t ipc_cursor_id) { | |
254 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); | |
255 return cursor_dispatcher_host_->map_.Lookup(ipc_cursor_id); | |
256 } | |
257 | |
258 ::IndexedDBDatabaseMetadata IndexedDBDispatcherHost::ConvertMetadata( | |
259 const content::IndexedDBDatabaseMetadata& web_metadata) { | |
260 ::IndexedDBDatabaseMetadata metadata; | |
261 metadata.id = web_metadata.id; | |
262 metadata.name = web_metadata.name; | |
263 metadata.version = web_metadata.version; | |
264 metadata.max_object_store_id = web_metadata.max_object_store_id; | |
265 | |
266 for (const auto& iter : web_metadata.object_stores) { | |
267 const content::IndexedDBObjectStoreMetadata& web_store_metadata = | |
268 iter.second; | |
269 ::IndexedDBObjectStoreMetadata idb_store_metadata; | |
270 idb_store_metadata.id = web_store_metadata.id; | |
271 idb_store_metadata.name = web_store_metadata.name; | |
272 idb_store_metadata.key_path = web_store_metadata.key_path; | |
273 idb_store_metadata.auto_increment = web_store_metadata.auto_increment; | |
274 idb_store_metadata.max_index_id = web_store_metadata.max_index_id; | |
275 | |
276 for (const auto& index_iter : web_store_metadata.indexes) { | |
277 const content::IndexedDBIndexMetadata& web_index_metadata = | |
278 index_iter.second; | |
279 ::IndexedDBIndexMetadata idb_index_metadata; | |
280 idb_index_metadata.id = web_index_metadata.id; | |
281 idb_index_metadata.name = web_index_metadata.name; | |
282 idb_index_metadata.key_path = web_index_metadata.key_path; | |
283 idb_index_metadata.unique = web_index_metadata.unique; | |
284 idb_index_metadata.multi_entry = web_index_metadata.multi_entry; | |
285 idb_store_metadata.indexes.push_back(idb_index_metadata); | |
286 } | |
287 metadata.object_stores.push_back(idb_store_metadata); | |
288 } | |
289 return metadata; | |
290 } | |
291 | |
292 IndexedDBMsg_ObserverChanges IndexedDBDispatcherHost::ConvertObserverChanges( | |
293 std::unique_ptr<IndexedDBObserverChanges> changes) { | |
294 IndexedDBMsg_ObserverChanges idb_changes; | |
295 idb_changes.observation_index = changes->release_observation_indices_map(); | |
296 for (const auto& observation : changes->release_observations()) | |
297 idb_changes.observations.push_back(ConvertObservation(observation.get())); | |
298 return idb_changes; | |
299 } | |
300 | |
301 IndexedDBMsg_Observation IndexedDBDispatcherHost::ConvertObservation( | |
302 const IndexedDBObservation* observation) { | |
303 // TODO(palakj): Modify function for indexed_db_value. Issue crbug.com/609934. | |
304 IndexedDBMsg_Observation idb_observation; | |
305 idb_observation.object_store_id = observation->object_store_id(); | |
306 idb_observation.type = observation->type(); | |
307 idb_observation.key_range = observation->key_range(); | |
308 return idb_observation; | |
309 } | |
310 | |
311 void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames( | |
312 const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& params) { | |
313 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); | |
314 | |
315 if (!IsValidOrigin(params.origin)) { | |
316 bad_message::ReceivedBadMessage(this, bad_message::IDBDH_INVALID_ORIGIN); | |
317 return; | |
318 } | |
319 | |
320 base::FilePath indexed_db_path = indexed_db_context_->data_path(); | |
321 context()->GetIDBFactory()->GetDatabaseNames( | |
322 new IndexedDBCallbacks(this, params.ipc_thread_id, | |
323 params.ipc_callbacks_id), | |
324 params.origin, indexed_db_path, request_context_getter_); | |
325 } | |
326 | |
327 void IndexedDBDispatcherHost::OnIDBFactoryOpen( | |
328 const IndexedDBHostMsg_FactoryOpen_Params& params) { | |
329 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); | |
330 | |
331 if (!IsValidOrigin(params.origin)) { | |
332 bad_message::ReceivedBadMessage(this, bad_message::IDBDH_INVALID_ORIGIN); | |
333 return; | |
334 } | |
335 | |
336 base::TimeTicks begin_time = base::TimeTicks::Now(); | |
337 base::FilePath indexed_db_path = indexed_db_context_->data_path(); | |
338 | |
339 int64_t host_transaction_id = HostTransactionId(params.transaction_id); | |
340 | |
341 // TODO(dgrogan): Don't let a non-existing database be opened (and therefore | |
342 // created) if this origin is already over quota. | |
343 scoped_refptr<IndexedDBCallbacks> callbacks = new IndexedDBCallbacks( | |
344 this, params.ipc_thread_id, params.ipc_callbacks_id, | |
345 params.ipc_database_callbacks_id, host_transaction_id, params.origin); | |
346 callbacks->SetConnectionOpenStartTime(begin_time); | |
347 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks = | |
348 new IndexedDBDatabaseCallbacks( | |
349 this, params.ipc_thread_id, params.ipc_database_callbacks_id); | |
350 std::unique_ptr<IndexedDBPendingConnection> connection = | |
351 base::MakeUnique<IndexedDBPendingConnection>( | |
352 callbacks, database_callbacks, ipc_process_id_, host_transaction_id, | |
353 params.version); | |
354 DCHECK(request_context_getter_); | |
355 context()->GetIDBFactory()->Open(params.name, std::move(connection), | |
356 request_context_getter_, params.origin, | |
357 indexed_db_path); | |
358 } | |
359 | |
360 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase( | |
361 const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) { | |
362 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); | |
363 | |
364 if (!IsValidOrigin(params.origin)) { | |
365 bad_message::ReceivedBadMessage(this, bad_message::IDBDH_INVALID_ORIGIN); | |
366 return; | |
367 } | |
368 | |
369 base::FilePath indexed_db_path = indexed_db_context_->data_path(); | |
370 DCHECK(request_context_getter_); | |
371 context()->GetIDBFactory()->DeleteDatabase( | |
372 params.name, request_context_getter_, | |
373 new IndexedDBCallbacks(this, params.ipc_thread_id, | |
374 params.ipc_callbacks_id), | |
375 params.origin, indexed_db_path); | |
376 } | |
377 | |
378 // OnPutHelper exists only to allow us to hop threads while holding a reference | |
379 // to the IndexedDBDispatcherHost. | |
380 void IndexedDBDispatcherHost::OnPutHelper( | |
381 const IndexedDBHostMsg_DatabasePut_Params& params, | |
382 std::vector<storage::BlobDataHandle*> handles) { | |
383 database_dispatcher_host_->OnPut(params, handles); | |
384 } | |
385 | |
386 void IndexedDBDispatcherHost::OnAckReceivedBlobs( | |
387 const std::vector<std::string>& uuids) { | |
388 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
389 for (const auto& uuid : uuids) | |
390 DropBlobData(uuid); | |
391 } | |
392 | |
393 void IndexedDBDispatcherHost::FinishTransaction(int64_t host_transaction_id, | |
394 bool committed) { | |
395 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); | |
396 if (!database_dispatcher_host_) | |
397 return; | |
398 TransactionIDToOriginMap& transaction_origin_map = | |
399 database_dispatcher_host_->transaction_origin_map_; | |
400 TransactionIDToSizeMap& transaction_size_map = | |
401 database_dispatcher_host_->transaction_size_map_; | |
402 TransactionIDToDatabaseIDMap& transaction_database_map = | |
403 database_dispatcher_host_->transaction_database_map_; | |
404 if (committed) | |
405 context()->TransactionComplete(transaction_origin_map[host_transaction_id]); | |
406 transaction_origin_map.erase(host_transaction_id); | |
407 transaction_size_map.erase(host_transaction_id); | |
408 transaction_database_map.erase(host_transaction_id); | |
409 } | |
410 | |
411 ////////////////////////////////////////////////////////////////////// | |
412 // Helper templates. | |
413 // | |
414 | |
415 template <typename ObjectType> | |
416 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess( | |
417 IDMap<ObjectType, IDMapOwnPointer>* map, | |
418 int32_t ipc_return_object_id) { | |
419 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); | |
420 ObjectType* return_object = map->Lookup(ipc_return_object_id); | |
421 if (!return_object) { | |
422 NOTREACHED() << "Uh oh, couldn't find object with id " | |
423 << ipc_return_object_id; | |
424 bad_message::ReceivedBadMessage(this, bad_message::IDBDH_GET_OR_TERMINATE); | |
425 } | |
426 return return_object; | |
427 } | |
428 | |
429 template <typename ObjectType> | |
430 ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess( | |
431 RefIDMap<ObjectType>* map, | |
432 int32_t ipc_return_object_id) { | |
433 DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); | |
434 ObjectType* return_object = map->Lookup(ipc_return_object_id); | |
435 if (!return_object) { | |
436 NOTREACHED() << "Uh oh, couldn't find object with id " | |
437 << ipc_return_object_id; | |
438 bad_message::ReceivedBadMessage(this, bad_message::IDBDH_GET_OR_TERMINATE); | |
439 } | |
440 return return_object; | |
441 } | |
442 | |
443 template <typename MapType> | |
444 void IndexedDBDispatcherHost::DestroyObject(MapType* map, | |
445 int32_t ipc_object_id) { | |
446 GetOrTerminateProcess(map, ipc_object_id); | |
447 map->Remove(ipc_object_id); | |
448 } | |
449 | |
450 ////////////////////////////////////////////////////////////////////// | |
451 // IndexedDBDispatcherHost::DatabaseDispatcherHost | |
452 // | |
453 | |
454 IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost( | |
455 IndexedDBDispatcherHost* parent) | |
456 : parent_(parent), weak_factory_(this) { | |
457 map_.set_check_on_null_data(true); | |
458 } | |
459 | |
460 IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() { | |
461 // TODO(alecflett): uncomment these when we find the source of these leaks. | |
462 // DCHECK(transaction_size_map_.empty()); | |
463 // DCHECK(transaction_origin_map_.empty()); | |
464 } | |
465 | |
466 void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() { | |
467 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
468 // Abort outstanding transactions started by connections in the associated | |
469 // front-end to unblock later transactions. This should only occur on unclean | |
470 // (crash) or abrupt (process-kill) shutdowns. | |
471 for (TransactionIDToDatabaseIDMap::iterator iter = | |
472 transaction_database_map_.begin(); | |
473 iter != transaction_database_map_.end();) { | |
474 int64_t transaction_id = iter->first; | |
475 int32_t ipc_database_id = iter->second; | |
476 ++iter; | |
477 IndexedDBConnection* connection = map_.Lookup(ipc_database_id); | |
478 if (connection && connection->IsConnected()) { | |
479 connection->database()->Abort( | |
480 transaction_id, | |
481 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError)); | |
482 } | |
483 } | |
484 DCHECK(transaction_database_map_.empty()); | |
485 | |
486 for (const auto& iter : database_origin_map_) { | |
487 IndexedDBConnection* connection = map_.Lookup(iter.first); | |
488 if (connection && connection->IsConnected()) { | |
489 connection->Close(); | |
490 parent_->context()->ConnectionClosed(iter.second, connection); | |
491 } | |
492 } | |
493 } | |
494 | |
495 bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived( | |
496 const IPC::Message& message) { | |
497 DCHECK((message.type() == IndexedDBHostMsg_DatabasePut::ID || | |
498 message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID) || | |
499 parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
500 | |
501 bool handled = true; | |
502 IPC_BEGIN_MESSAGE_MAP( | |
503 IndexedDBDispatcherHost::DatabaseDispatcherHost, message) | |
504 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore, | |
505 OnCreateObjectStore) | |
506 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore, | |
507 OnDeleteObjectStore) | |
508 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction, | |
509 OnCreateTransaction) | |
510 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose) | |
511 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored, | |
512 OnVersionChangeIgnored) | |
513 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed) | |
514 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseObserve, OnObserve) | |
515 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseUnobserve, OnUnobserve) | |
516 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet) | |
517 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGetAll, OnGetAll) | |
518 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper) | |
519 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys) | |
520 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady, | |
521 OnSetIndexesReady) | |
522 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseOpenCursor, OnOpenCursor) | |
523 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCount, OnCount) | |
524 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteRange, OnDeleteRange) | |
525 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClear, OnClear) | |
526 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateIndex, OnCreateIndex) | |
527 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteIndex, OnDeleteIndex) | |
528 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseAbort, OnAbort) | |
529 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCommit, OnCommit) | |
530 IPC_MESSAGE_UNHANDLED(handled = false) | |
531 IPC_END_MESSAGE_MAP() | |
532 | |
533 return handled; | |
534 } | |
535 | |
536 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore( | |
537 const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) { | |
538 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
539 IndexedDBConnection* connection = | |
540 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
541 if (!connection || !connection->IsConnected()) | |
542 return; | |
543 | |
544 int64_t host_transaction_id = | |
545 parent_->HostTransactionId(params.transaction_id); | |
546 connection->database()->CreateObjectStore(host_transaction_id, | |
547 params.object_store_id, | |
548 params.name, | |
549 params.key_path, | |
550 params.auto_increment); | |
551 } | |
552 | |
553 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore( | |
554 int32_t ipc_database_id, | |
555 int64_t transaction_id, | |
556 int64_t object_store_id) { | |
557 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
558 IndexedDBConnection* connection = | |
559 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
560 if (!connection || !connection->IsConnected()) | |
561 return; | |
562 | |
563 connection->database()->DeleteObjectStore( | |
564 parent_->HostTransactionId(transaction_id), object_store_id); | |
565 } | |
566 | |
567 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction( | |
568 const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) { | |
569 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
570 IndexedDBConnection* connection = | |
571 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
572 if (!connection || !connection->IsConnected()) | |
573 return; | |
574 | |
575 int64_t host_transaction_id = | |
576 parent_->HostTransactionId(params.transaction_id); | |
577 | |
578 if (base::ContainsKey(transaction_database_map_, host_transaction_id)) { | |
579 DLOG(ERROR) << "Duplicate host_transaction_id."; | |
580 return; | |
581 } | |
582 | |
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_origin_map_[params.ipc_database_id]); | |
588 } | |
589 | |
590 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose( | |
591 int32_t ipc_database_id) { | |
592 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
593 IndexedDBConnection* connection = | |
594 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
595 if (!connection || !connection->IsConnected()) | |
596 return; | |
597 connection->Close(); | |
598 } | |
599 | |
600 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored( | |
601 int32_t ipc_database_id) { | |
602 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
603 IndexedDBConnection* connection = | |
604 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
605 if (!connection || !connection->IsConnected()) | |
606 return; | |
607 connection->VersionChangeIgnored(); | |
608 } | |
609 | |
610 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed( | |
611 int32_t ipc_object_id) { | |
612 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
613 IndexedDBConnection* connection = | |
614 parent_->GetOrTerminateProcess(&map_, ipc_object_id); | |
615 if (!connection) | |
616 return; | |
617 if (connection->IsConnected()) | |
618 connection->Close(); | |
619 parent_->context()->ConnectionClosed(database_origin_map_[ipc_object_id], | |
620 connection); | |
621 database_origin_map_.erase(ipc_object_id); | |
622 parent_->DestroyObject(&map_, ipc_object_id); | |
623 } | |
624 | |
625 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnObserve( | |
626 const IndexedDBHostMsg_DatabaseObserve_Params& params) { | |
627 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
628 IndexedDBConnection* connection = | |
629 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
630 if (!connection || !connection->IsConnected()) | |
631 return; | |
632 IndexedDBObserver::Options options(params.include_transaction, | |
633 params.no_records, params.values, | |
634 params.operation_types); | |
635 connection->database()->AddPendingObserver( | |
636 parent_->HostTransactionId(params.transaction_id), params.observer_id, | |
637 options); | |
638 } | |
639 | |
640 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnUnobserve( | |
641 int32_t ipc_database_id, | |
642 const std::vector<int32_t>& observer_ids_to_remove) { | |
643 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
644 DCHECK(!observer_ids_to_remove.empty()); | |
645 IndexedDBConnection* connection = | |
646 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
647 if (!connection || !connection->IsConnected()) | |
648 return; | |
649 connection->RemoveObservers(observer_ids_to_remove); | |
650 } | |
651 | |
652 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet( | |
653 const IndexedDBHostMsg_DatabaseGet_Params& params) { | |
654 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
655 IndexedDBConnection* connection = | |
656 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
657 if (!connection || !connection->IsConnected()) | |
658 return; | |
659 | |
660 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks( | |
661 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); | |
662 connection->database()->Get( | |
663 parent_->HostTransactionId(params.transaction_id), params.object_store_id, | |
664 params.index_id, base::MakeUnique<IndexedDBKeyRange>(params.key_range), | |
665 params.key_only, callbacks); | |
666 } | |
667 | |
668 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGetAll( | |
669 const IndexedDBHostMsg_DatabaseGetAll_Params& params) { | |
670 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
671 IndexedDBConnection* connection = | |
672 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
673 if (!connection || !connection->IsConnected()) | |
674 return; | |
675 | |
676 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks( | |
677 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); | |
678 connection->database()->GetAll( | |
679 parent_->HostTransactionId(params.transaction_id), params.object_store_id, | |
680 params.index_id, base::MakeUnique<IndexedDBKeyRange>(params.key_range), | |
681 params.key_only, params.max_count, callbacks); | |
682 } | |
683 | |
684 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper( | |
685 const IndexedDBHostMsg_DatabasePut_Params& params) { | |
686 std::vector<storage::BlobDataHandle*> handles; | |
687 for (size_t i = 0; i < params.value.blob_or_file_info.size(); ++i) { | |
688 const IndexedDBMsg_BlobOrFileInfo& info = params.value.blob_or_file_info[i]; | |
689 handles.push_back(parent_->blob_storage_context_->context() | |
690 ->GetBlobDataFromUUID(info.uuid) | |
691 .release()); | |
692 } | |
693 parent_->context()->TaskRunner()->PostTask( | |
694 FROM_HERE, base::Bind(&IndexedDBDispatcherHost::OnPutHelper, parent_, | |
695 params, handles)); | |
696 } | |
697 | |
698 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut( | |
699 const IndexedDBHostMsg_DatabasePut_Params& params, | |
700 std::vector<storage::BlobDataHandle*> handles) { | |
701 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
702 | |
703 ScopedVector<storage::BlobDataHandle> scoped_handles; | |
704 scoped_handles.swap(handles); | |
705 | |
706 IndexedDBConnection* connection = | |
707 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
708 if (!connection || !connection->IsConnected()) | |
709 return; | |
710 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks( | |
711 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); | |
712 | |
713 int64_t host_transaction_id = | |
714 parent_->HostTransactionId(params.transaction_id); | |
715 | |
716 std::vector<IndexedDBBlobInfo> blob_info( | |
717 params.value.blob_or_file_info.size()); | |
718 | |
719 ChildProcessSecurityPolicyImpl* policy = | |
720 ChildProcessSecurityPolicyImpl::GetInstance(); | |
721 | |
722 for (size_t i = 0; i < params.value.blob_or_file_info.size(); ++i) { | |
723 const IndexedDBMsg_BlobOrFileInfo& info = params.value.blob_or_file_info[i]; | |
724 if (info.is_file) { | |
725 base::FilePath path; | |
726 if (!info.file_path.empty()) { | |
727 path = base::FilePath::FromUTF16Unsafe(info.file_path); | |
728 if (!policy->CanReadFile(parent_->ipc_process_id_, path)) { | |
729 bad_message::ReceivedBadMessage(parent_, | |
730 bad_message::IDBDH_CAN_READ_FILE); | |
731 return; | |
732 } | |
733 } | |
734 blob_info[i] = | |
735 IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type); | |
736 if (info.size != static_cast<uint64_t>(-1)) { | |
737 blob_info[i].set_last_modified( | |
738 base::Time::FromDoubleT(info.last_modified)); | |
739 blob_info[i].set_size(info.size); | |
740 } | |
741 } else { | |
742 blob_info[i] = IndexedDBBlobInfo(info.uuid, info.mime_type, info.size); | |
743 } | |
744 } | |
745 | |
746 // TODO(alecflett): Avoid a copy here. | |
747 IndexedDBValue value; | |
748 value.bits = params.value.bits; | |
749 value.blob_info.swap(blob_info); | |
750 connection->database()->Put(host_transaction_id, params.object_store_id, | |
751 &value, &scoped_handles, | |
752 base::MakeUnique<IndexedDBKey>(params.key), | |
753 params.put_mode, callbacks, params.index_keys); | |
754 // Size can't be big enough to overflow because it represents the | |
755 // actual bytes passed through IPC. | |
756 transaction_size_map_[host_transaction_id] += params.value.bits.size(); | |
757 } | |
758 | |
759 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys( | |
760 const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) { | |
761 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
762 IndexedDBConnection* connection = | |
763 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
764 if (!connection || !connection->IsConnected()) | |
765 return; | |
766 | |
767 int64_t host_transaction_id = | |
768 parent_->HostTransactionId(params.transaction_id); | |
769 connection->database()->SetIndexKeys( | |
770 host_transaction_id, params.object_store_id, | |
771 base::MakeUnique<IndexedDBKey>(params.primary_key), params.index_keys); | |
772 } | |
773 | |
774 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady( | |
775 int32_t ipc_database_id, | |
776 int64_t transaction_id, | |
777 int64_t object_store_id, | |
778 const std::vector<int64_t>& index_ids) { | |
779 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
780 IndexedDBConnection* connection = | |
781 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
782 if (!connection || !connection->IsConnected()) | |
783 return; | |
784 | |
785 connection->database()->SetIndexesReady( | |
786 parent_->HostTransactionId(transaction_id), object_store_id, index_ids); | |
787 } | |
788 | |
789 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor( | |
790 const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) { | |
791 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
792 IndexedDBConnection* connection = | |
793 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
794 if (!connection || !connection->IsConnected()) | |
795 return; | |
796 | |
797 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks( | |
798 parent_, params.ipc_thread_id, params.ipc_callbacks_id, -1)); | |
799 connection->database()->OpenCursor( | |
800 parent_->HostTransactionId(params.transaction_id), params.object_store_id, | |
801 params.index_id, base::MakeUnique<IndexedDBKeyRange>(params.key_range), | |
802 params.direction, params.key_only, params.task_type, callbacks); | |
803 } | |
804 | |
805 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount( | |
806 const IndexedDBHostMsg_DatabaseCount_Params& params) { | |
807 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
808 IndexedDBConnection* connection = | |
809 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
810 if (!connection || !connection->IsConnected()) | |
811 return; | |
812 | |
813 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks( | |
814 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); | |
815 connection->database()->Count( | |
816 parent_->HostTransactionId(params.transaction_id), params.object_store_id, | |
817 params.index_id, base::MakeUnique<IndexedDBKeyRange>(params.key_range), | |
818 callbacks); | |
819 } | |
820 | |
821 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange( | |
822 const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) { | |
823 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
824 IndexedDBConnection* connection = | |
825 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
826 if (!connection || !connection->IsConnected()) | |
827 return; | |
828 | |
829 scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks( | |
830 parent_, params.ipc_thread_id, params.ipc_callbacks_id)); | |
831 connection->database()->DeleteRange( | |
832 parent_->HostTransactionId(params.transaction_id), params.object_store_id, | |
833 base::MakeUnique<IndexedDBKeyRange>(params.key_range), callbacks); | |
834 } | |
835 | |
836 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear( | |
837 int32_t ipc_thread_id, | |
838 int32_t ipc_callbacks_id, | |
839 int32_t ipc_database_id, | |
840 int64_t transaction_id, | |
841 int64_t object_store_id) { | |
842 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
843 IndexedDBConnection* connection = | |
844 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
845 if (!connection || !connection->IsConnected()) | |
846 return; | |
847 | |
848 scoped_refptr<IndexedDBCallbacks> callbacks( | |
849 new IndexedDBCallbacks(parent_, ipc_thread_id, ipc_callbacks_id)); | |
850 | |
851 connection->database()->Clear( | |
852 parent_->HostTransactionId(transaction_id), object_store_id, callbacks); | |
853 } | |
854 | |
855 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort( | |
856 int32_t ipc_database_id, | |
857 int64_t transaction_id) { | |
858 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
859 IndexedDBConnection* connection = | |
860 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
861 if (!connection || !connection->IsConnected()) | |
862 return; | |
863 | |
864 connection->database()->Abort(parent_->HostTransactionId(transaction_id)); | |
865 } | |
866 | |
867 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit( | |
868 int32_t ipc_database_id, | |
869 int64_t transaction_id) { | |
870 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
871 IndexedDBConnection* connection = | |
872 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
873 if (!connection || !connection->IsConnected()) | |
874 return; | |
875 | |
876 int64_t host_transaction_id = parent_->HostTransactionId(transaction_id); | |
877 // May have been aborted by back end before front-end could request commit. | |
878 if (!base::ContainsKey(transaction_size_map_, host_transaction_id)) | |
879 return; | |
880 int64_t transaction_size = transaction_size_map_[host_transaction_id]; | |
881 | |
882 // Always allow empty or delete-only transactions. | |
883 if (!transaction_size) { | |
884 connection->database()->Commit(host_transaction_id); | |
885 return; | |
886 } | |
887 | |
888 parent_->context()->quota_manager_proxy()->GetUsageAndQuota( | |
889 parent_->context()->TaskRunner(), | |
890 GURL(transaction_origin_map_[host_transaction_id].Serialize()), | |
891 storage::kStorageTypeTemporary, | |
892 base::Bind(&IndexedDBDispatcherHost::DatabaseDispatcherHost:: | |
893 OnGotUsageAndQuotaForCommit, | |
894 weak_factory_.GetWeakPtr(), ipc_database_id, transaction_id)); | |
895 } | |
896 | |
897 void IndexedDBDispatcherHost::DatabaseDispatcherHost:: | |
898 OnGotUsageAndQuotaForCommit(int32_t ipc_database_id, | |
899 int64_t transaction_id, | |
900 storage::QuotaStatusCode status, | |
901 int64_t usage, | |
902 int64_t quota) { | |
903 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
904 IndexedDBConnection* connection = map_.Lookup(ipc_database_id); | |
905 // May have disconnected while quota check was pending. | |
906 if (!connection || !connection->IsConnected()) | |
907 return; | |
908 int64_t host_transaction_id = parent_->HostTransactionId(transaction_id); | |
909 // May have aborted while quota check was pending. | |
910 if (!base::ContainsKey(transaction_size_map_, host_transaction_id)) | |
911 return; | |
912 int64_t transaction_size = transaction_size_map_[host_transaction_id]; | |
913 | |
914 if (status == storage::kQuotaStatusOk && | |
915 usage + transaction_size <= quota) { | |
916 connection->database()->Commit(host_transaction_id); | |
917 } else { | |
918 connection->database()->Abort( | |
919 host_transaction_id, | |
920 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError)); | |
921 } | |
922 } | |
923 | |
924 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex( | |
925 const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) { | |
926 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
927 IndexedDBConnection* connection = | |
928 parent_->GetOrTerminateProcess(&map_, params.ipc_database_id); | |
929 if (!connection || !connection->IsConnected()) | |
930 return; | |
931 | |
932 int64_t host_transaction_id = | |
933 parent_->HostTransactionId(params.transaction_id); | |
934 connection->database()->CreateIndex(host_transaction_id, | |
935 params.object_store_id, | |
936 params.index_id, | |
937 params.name, | |
938 params.key_path, | |
939 params.unique, | |
940 params.multi_entry); | |
941 } | |
942 | |
943 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex( | |
944 int32_t ipc_database_id, | |
945 int64_t transaction_id, | |
946 int64_t object_store_id, | |
947 int64_t index_id) { | |
948 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
949 IndexedDBConnection* connection = | |
950 parent_->GetOrTerminateProcess(&map_, ipc_database_id); | |
951 if (!connection || !connection->IsConnected()) | |
952 return; | |
953 | |
954 connection->database()->DeleteIndex( | |
955 parent_->HostTransactionId(transaction_id), object_store_id, index_id); | |
956 } | |
957 | |
958 ////////////////////////////////////////////////////////////////////// | |
959 // IndexedDBDispatcherHost::CursorDispatcherHost | |
960 // | |
961 | |
962 IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost( | |
963 IndexedDBDispatcherHost* parent) | |
964 : parent_(parent) { | |
965 map_.set_check_on_null_data(true); | |
966 } | |
967 | |
968 IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {} | |
969 | |
970 bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived( | |
971 const IPC::Message& message) { | |
972 bool handled = true; | |
973 IPC_BEGIN_MESSAGE_MAP( | |
974 IndexedDBDispatcherHost::CursorDispatcherHost, message) | |
975 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorAdvance, OnAdvance) | |
976 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue) | |
977 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetch, OnPrefetch) | |
978 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorPrefetchReset, OnPrefetchReset) | |
979 IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed) | |
980 IPC_MESSAGE_UNHANDLED(handled = false) | |
981 IPC_END_MESSAGE_MAP() | |
982 | |
983 DCHECK(!handled || | |
984 parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
985 | |
986 return handled; | |
987 } | |
988 | |
989 void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance( | |
990 int32_t ipc_cursor_id, | |
991 int32_t ipc_thread_id, | |
992 int32_t ipc_callbacks_id, | |
993 uint32_t count) { | |
994 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
995 IndexedDBCursor* idb_cursor = | |
996 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); | |
997 if (!idb_cursor) | |
998 return; | |
999 | |
1000 idb_cursor->Advance( | |
1001 count, | |
1002 new IndexedDBCallbacks( | |
1003 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id)); | |
1004 } | |
1005 | |
1006 void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue( | |
1007 int32_t ipc_cursor_id, | |
1008 int32_t ipc_thread_id, | |
1009 int32_t ipc_callbacks_id, | |
1010 const IndexedDBKey& key, | |
1011 const IndexedDBKey& primary_key) { | |
1012 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
1013 IndexedDBCursor* idb_cursor = | |
1014 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); | |
1015 if (!idb_cursor) | |
1016 return; | |
1017 | |
1018 idb_cursor->Continue(key.IsValid() ? base::MakeUnique<IndexedDBKey>(key) | |
1019 : std::unique_ptr<IndexedDBKey>(), | |
1020 primary_key.IsValid() | |
1021 ? base::MakeUnique<IndexedDBKey>(primary_key) | |
1022 : std::unique_ptr<IndexedDBKey>(), | |
1023 new IndexedDBCallbacks(parent_, ipc_thread_id, | |
1024 ipc_callbacks_id, ipc_cursor_id)); | |
1025 } | |
1026 | |
1027 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch( | |
1028 int32_t ipc_cursor_id, | |
1029 int32_t ipc_thread_id, | |
1030 int32_t ipc_callbacks_id, | |
1031 int n) { | |
1032 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
1033 IndexedDBCursor* idb_cursor = | |
1034 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); | |
1035 if (!idb_cursor) | |
1036 return; | |
1037 | |
1038 idb_cursor->PrefetchContinue( | |
1039 n, | |
1040 new IndexedDBCallbacks( | |
1041 parent_, ipc_thread_id, ipc_callbacks_id, ipc_cursor_id)); | |
1042 } | |
1043 | |
1044 void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset( | |
1045 int32_t ipc_cursor_id, | |
1046 int used_prefetches, | |
1047 int unused_prefetches) { | |
1048 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
1049 IndexedDBCursor* idb_cursor = | |
1050 parent_->GetOrTerminateProcess(&map_, ipc_cursor_id); | |
1051 if (!idb_cursor) | |
1052 return; | |
1053 | |
1054 leveldb::Status s = | |
1055 idb_cursor->PrefetchReset(used_prefetches, unused_prefetches); | |
1056 // TODO(cmumford): Handle this error (crbug.com/363397) | |
1057 if (!s.ok()) | |
1058 DLOG(ERROR) << "Unable to reset prefetch"; | |
1059 } | |
1060 | |
1061 void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed( | |
1062 int32_t ipc_object_id) { | |
1063 DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread()); | |
1064 parent_->DestroyObject(&map_, ipc_object_id); | |
1065 } | |
1066 | |
1067 } // namespace content | |
OLD | NEW |