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_callbacks.h"
6
7#include <algorithm>
8
9#include "base/guid.h"
10#include "base/metrics/histogram.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/time/time.h"
13#include "content/browser/child_process_security_policy_impl.h"
14#include "content/browser/fileapi/fileapi_message_filter.h"
15#include "content/browser/indexed_db/indexed_db_blob_info.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_database_error.h"
21#include "content/browser/indexed_db/indexed_db_metadata.h"
22#include "content/browser/indexed_db/indexed_db_value.h"
23#include "content/common/indexed_db/indexed_db_constants.h"
24#include "content/common/indexed_db/indexed_db_messages.h"
25#include "storage/browser/blob/blob_storage_context.h"
26#include "storage/browser/quota/quota_manager.h"
27#include "storage/common/blob/blob_data.h"
28#include "storage/common/blob/shareable_file_reference.h"
29
30using storage::ShareableFileReference;
31
32namespace content {
33
34namespace {
35const int32 kNoCursor = -1;
36const int32 kNoDatabaseCallbacks = -1;
37const int64 kNoTransaction = -1;
38}
39
40IndexedDBCallbacks::IndexedDBCallbacks(IndexedDBDispatcherHost* dispatcher_host,
41                                       int32 ipc_thread_id,
42                                       int32 ipc_callbacks_id)
43    : dispatcher_host_(dispatcher_host),
44      ipc_callbacks_id_(ipc_callbacks_id),
45      ipc_thread_id_(ipc_thread_id),
46      ipc_cursor_id_(kNoCursor),
47      host_transaction_id_(kNoTransaction),
48      ipc_database_id_(kNoDatabase),
49      ipc_database_callbacks_id_(kNoDatabaseCallbacks),
50      data_loss_(blink::WebIDBDataLossNone),
51      sent_blocked_(false) {
52}
53
54IndexedDBCallbacks::IndexedDBCallbacks(IndexedDBDispatcherHost* dispatcher_host,
55                                       int32 ipc_thread_id,
56                                       int32 ipc_callbacks_id,
57                                       int32 ipc_cursor_id)
58    : dispatcher_host_(dispatcher_host),
59      ipc_callbacks_id_(ipc_callbacks_id),
60      ipc_thread_id_(ipc_thread_id),
61      ipc_cursor_id_(ipc_cursor_id),
62      host_transaction_id_(kNoTransaction),
63      ipc_database_id_(kNoDatabase),
64      ipc_database_callbacks_id_(kNoDatabaseCallbacks),
65      data_loss_(blink::WebIDBDataLossNone),
66      sent_blocked_(false) {
67}
68
69IndexedDBCallbacks::IndexedDBCallbacks(IndexedDBDispatcherHost* dispatcher_host,
70                                       int32 ipc_thread_id,
71                                       int32 ipc_callbacks_id,
72                                       int32 ipc_database_callbacks_id,
73                                       int64 host_transaction_id,
74                                       const GURL& origin_url)
75    : dispatcher_host_(dispatcher_host),
76      ipc_callbacks_id_(ipc_callbacks_id),
77      ipc_thread_id_(ipc_thread_id),
78      ipc_cursor_id_(kNoCursor),
79      host_transaction_id_(host_transaction_id),
80      origin_url_(origin_url),
81      ipc_database_id_(kNoDatabase),
82      ipc_database_callbacks_id_(ipc_database_callbacks_id),
83      data_loss_(blink::WebIDBDataLossNone),
84      sent_blocked_(false) {
85}
86
87IndexedDBCallbacks::~IndexedDBCallbacks() {}
88
89void IndexedDBCallbacks::OnError(const IndexedDBDatabaseError& error) {
90  DCHECK(dispatcher_host_.get());
91
92  dispatcher_host_->Send(new IndexedDBMsg_CallbacksError(
93      ipc_thread_id_, ipc_callbacks_id_, error.code(), error.message()));
94  dispatcher_host_ = NULL;
95
96  if (!connection_open_start_time_.is_null()) {
97    UMA_HISTOGRAM_MEDIUM_TIMES(
98        "WebCore.IndexedDB.OpenTime.Error",
99        base::TimeTicks::Now() - connection_open_start_time_);
100    connection_open_start_time_ = base::TimeTicks();
101  }
102}
103
104void IndexedDBCallbacks::OnSuccess(const std::vector<base::string16>& value) {
105  DCHECK(dispatcher_host_.get());
106
107  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
108  DCHECK_EQ(kNoTransaction, host_transaction_id_);
109  DCHECK_EQ(kNoDatabase, ipc_database_id_);
110  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
111  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
112
113  std::vector<base::string16> list;
114  for (unsigned i = 0; i < value.size(); ++i)
115    list.push_back(value[i]);
116
117  dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessStringList(
118      ipc_thread_id_, ipc_callbacks_id_, list));
119  dispatcher_host_ = NULL;
120}
121
122void IndexedDBCallbacks::OnBlocked(int64 existing_version) {
123  DCHECK(dispatcher_host_.get());
124
125  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
126  // No transaction/db callbacks for DeleteDatabase.
127  DCHECK_EQ(kNoTransaction == host_transaction_id_,
128            kNoDatabaseCallbacks == ipc_database_callbacks_id_);
129  DCHECK_EQ(kNoDatabase, ipc_database_id_);
130
131  if (sent_blocked_)
132    return;
133
134  sent_blocked_ = true;
135  dispatcher_host_->Send(new IndexedDBMsg_CallbacksIntBlocked(
136      ipc_thread_id_, ipc_callbacks_id_, existing_version));
137
138  if (!connection_open_start_time_.is_null()) {
139    UMA_HISTOGRAM_MEDIUM_TIMES(
140        "WebCore.IndexedDB.OpenTime.Blocked",
141        base::TimeTicks::Now() - connection_open_start_time_);
142    connection_open_start_time_ = base::TimeTicks();
143  }
144}
145
146void IndexedDBCallbacks::OnDataLoss(blink::WebIDBDataLoss data_loss,
147                                    std::string data_loss_message) {
148  DCHECK_NE(blink::WebIDBDataLossNone, data_loss);
149  data_loss_ = data_loss;
150  data_loss_message_ = data_loss_message;
151}
152
153void IndexedDBCallbacks::OnUpgradeNeeded(
154    int64 old_version,
155    scoped_ptr<IndexedDBConnection> connection,
156    const IndexedDBDatabaseMetadata& metadata) {
157  DCHECK(dispatcher_host_.get());
158
159  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
160  DCHECK_NE(kNoTransaction, host_transaction_id_);
161  DCHECK_EQ(kNoDatabase, ipc_database_id_);
162  DCHECK_NE(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
163
164  dispatcher_host_->RegisterTransactionId(host_transaction_id_, origin_url_);
165  int32 ipc_database_id =
166      dispatcher_host_->Add(connection.release(), ipc_thread_id_, origin_url_);
167  if (ipc_database_id < 0)
168    return;
169  ipc_database_id_ = ipc_database_id;
170  IndexedDBMsg_CallbacksUpgradeNeeded_Params params;
171  params.ipc_thread_id = ipc_thread_id_;
172  params.ipc_callbacks_id = ipc_callbacks_id_;
173  params.ipc_database_id = ipc_database_id;
174  params.ipc_database_callbacks_id = ipc_database_callbacks_id_;
175  params.old_version = old_version;
176  params.idb_metadata = IndexedDBDispatcherHost::ConvertMetadata(metadata);
177  params.data_loss = data_loss_;
178  params.data_loss_message = data_loss_message_;
179  dispatcher_host_->Send(new IndexedDBMsg_CallbacksUpgradeNeeded(params));
180
181  if (!connection_open_start_time_.is_null()) {
182    UMA_HISTOGRAM_MEDIUM_TIMES(
183        "WebCore.IndexedDB.OpenTime.UpgradeNeeded",
184        base::TimeTicks::Now() - connection_open_start_time_);
185    connection_open_start_time_ = base::TimeTicks();
186  }
187}
188
189void IndexedDBCallbacks::OnSuccess(scoped_ptr<IndexedDBConnection> connection,
190                                   const IndexedDBDatabaseMetadata& metadata) {
191  DCHECK(dispatcher_host_.get());
192
193  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
194  DCHECK_NE(kNoTransaction, host_transaction_id_);
195  DCHECK_NE(ipc_database_id_ == kNoDatabase, !connection);
196  DCHECK_NE(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
197
198  scoped_refptr<IndexedDBCallbacks> self(this);
199
200  int32 ipc_object_id = kNoDatabase;
201  // Only register if the connection was not previously sent in OnUpgradeNeeded.
202  if (ipc_database_id_ == kNoDatabase) {
203    ipc_object_id = dispatcher_host_->Add(
204        connection.release(), ipc_thread_id_, origin_url_);
205  }
206
207  dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessIDBDatabase(
208      ipc_thread_id_,
209      ipc_callbacks_id_,
210      ipc_database_callbacks_id_,
211      ipc_object_id,
212      IndexedDBDispatcherHost::ConvertMetadata(metadata)));
213  dispatcher_host_ = NULL;
214
215  if (!connection_open_start_time_.is_null()) {
216    UMA_HISTOGRAM_MEDIUM_TIMES(
217        "WebCore.IndexedDB.OpenTime.Success",
218        base::TimeTicks::Now() - connection_open_start_time_);
219    connection_open_start_time_ = base::TimeTicks();
220  }
221}
222
223static std::string CreateBlobData(
224    const IndexedDBBlobInfo& blob_info,
225    scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
226    storage::BlobStorageContext* blob_storage_context,
227    base::TaskRunner* task_runner) {
228  std::string uuid = blob_info.uuid();
229  if (!uuid.empty()) {
230    // We're sending back a live blob, not a reference into our backing store.
231    scoped_ptr<storage::BlobDataHandle> blob_data_handle(
232        blob_storage_context->GetBlobDataFromUUID(uuid));
233    dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle.Pass());
234    return uuid;
235  }
236  scoped_refptr<ShareableFileReference> shareable_file =
237      ShareableFileReference::Get(blob_info.file_path());
238  if (!shareable_file.get()) {
239    shareable_file = ShareableFileReference::GetOrCreate(
240        blob_info.file_path(),
241        ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
242        task_runner);
243    if (!blob_info.release_callback().is_null())
244      shareable_file->AddFinalReleaseCallback(blob_info.release_callback());
245  }
246
247  uuid = base::GenerateGUID();
248  scoped_refptr<storage::BlobData> blob_data = new storage::BlobData(uuid);
249  blob_data->set_content_type(base::UTF16ToUTF8(blob_info.type()));
250  blob_data->AppendFile(
251      blob_info.file_path(), 0, blob_info.size(), blob_info.last_modified());
252  scoped_ptr<storage::BlobDataHandle> blob_data_handle(
253      blob_storage_context->AddFinishedBlob(blob_data.get()));
254  dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle.Pass());
255
256  return uuid;
257}
258
259static bool CreateAllBlobs(
260    const std::vector<IndexedDBBlobInfo>& blob_info,
261    std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info,
262    scoped_refptr<IndexedDBDispatcherHost> dispatcher_host) {
263  DCHECK_EQ(blob_info.size(), blob_or_file_info->size());
264  size_t i;
265  if (!dispatcher_host->blob_storage_context())
266    return false;
267  for (i = 0; i < blob_info.size(); ++i) {
268    (*blob_or_file_info)[i].uuid =
269        CreateBlobData(blob_info[i],
270                       dispatcher_host,
271                       dispatcher_host->blob_storage_context(),
272                       dispatcher_host->Context()->TaskRunner());
273  }
274  return true;
275}
276
277template <class ParamType, class MsgType>
278static void CreateBlobsAndSend(
279    ParamType* params,
280    scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
281    const std::vector<IndexedDBBlobInfo>& blob_info,
282    std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info) {
283  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
284  if (CreateAllBlobs(blob_info, blob_or_file_info, dispatcher_host))
285    dispatcher_host->Send(new MsgType(*params));
286}
287
288static void BlobLookupForCursorPrefetch(
289    IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params* params,
290    scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
291    const std::vector<IndexedDBValue>& values) {
292  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
293  DCHECK_EQ(values.size(), params->blob_or_file_infos.size());
294
295  std::vector<IndexedDBValue>::const_iterator value_iter;
296  std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >::iterator blob_iter;
297  for (value_iter = values.begin(), blob_iter =
298       params->blob_or_file_infos.begin(); value_iter != values.end();
299       ++value_iter, ++blob_iter) {
300    if (!CreateAllBlobs(value_iter->blob_info, &*blob_iter, dispatcher_host))
301      return;
302  }
303  dispatcher_host->Send(
304      new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params));
305}
306
307static void FillInBlobData(
308    const std::vector<IndexedDBBlobInfo>& blob_info,
309    std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info) {
310  for (std::vector<IndexedDBBlobInfo>::const_iterator iter = blob_info.begin();
311       iter != blob_info.end();
312       ++iter) {
313    if (iter->is_file()) {
314      IndexedDBMsg_BlobOrFileInfo info;
315      info.is_file = true;
316      info.mime_type = iter->type();
317      info.file_name = iter->file_name();
318      info.file_path = iter->file_path().AsUTF16Unsafe();
319      info.size = iter->size();
320      info.last_modified = iter->last_modified().ToDoubleT();
321      blob_or_file_info->push_back(info);
322    } else {
323      IndexedDBMsg_BlobOrFileInfo info;
324      info.mime_type = iter->type();
325      info.size = iter->size();
326      blob_or_file_info->push_back(info);
327    }
328  }
329}
330
331void IndexedDBCallbacks::RegisterBlobsAndSend(
332    const std::vector<IndexedDBBlobInfo>& blob_info,
333    const base::Closure& callback) {
334  std::vector<IndexedDBBlobInfo>::const_iterator iter;
335  for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) {
336    if (!iter->mark_used_callback().is_null())
337      iter->mark_used_callback().Run();
338  }
339  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
340  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback);
341}
342
343void IndexedDBCallbacks::OnSuccess(scoped_refptr<IndexedDBCursor> cursor,
344                                   const IndexedDBKey& key,
345                                   const IndexedDBKey& primary_key,
346                                   IndexedDBValue* value) {
347  DCHECK(dispatcher_host_.get());
348
349  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
350  DCHECK_EQ(kNoTransaction, host_transaction_id_);
351  DCHECK_EQ(kNoDatabase, ipc_database_id_);
352  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
353  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
354
355  int32 ipc_object_id = dispatcher_host_->Add(cursor.get());
356  scoped_ptr<IndexedDBMsg_CallbacksSuccessIDBCursor_Params> params(
357      new IndexedDBMsg_CallbacksSuccessIDBCursor_Params());
358  params->ipc_thread_id = ipc_thread_id_;
359  params->ipc_callbacks_id = ipc_callbacks_id_;
360  params->ipc_cursor_id = ipc_object_id;
361  params->key = key;
362  params->primary_key = primary_key;
363  if (value && !value->empty())
364    std::swap(params->value, value->bits);
365  // TODO(alecflett): Avoid a copy here: the whole params object is
366  // being copied into the message.
367  if (!value || value->blob_info.empty()) {
368    dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessIDBCursor(*params));
369  } else {
370    IndexedDBMsg_CallbacksSuccessIDBCursor_Params* p = params.get();
371    FillInBlobData(value->blob_info, &p->blob_or_file_info);
372    RegisterBlobsAndSend(
373        value->blob_info,
374        base::Bind(
375            CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessIDBCursor_Params,
376                               IndexedDBMsg_CallbacksSuccessIDBCursor>,
377            base::Owned(params.release()),
378            dispatcher_host_,
379            value->blob_info,
380            base::Unretained(&p->blob_or_file_info)));
381  }
382  dispatcher_host_ = NULL;
383}
384
385void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& key,
386                                   const IndexedDBKey& primary_key,
387                                   IndexedDBValue* value) {
388  DCHECK(dispatcher_host_.get());
389
390  DCHECK_NE(kNoCursor, ipc_cursor_id_);
391  DCHECK_EQ(kNoTransaction, host_transaction_id_);
392  DCHECK_EQ(kNoDatabase, ipc_database_id_);
393  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
394  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
395
396  IndexedDBCursor* idb_cursor =
397      dispatcher_host_->GetCursorFromId(ipc_cursor_id_);
398
399  DCHECK(idb_cursor);
400  if (!idb_cursor)
401    return;
402
403  scoped_ptr<IndexedDBMsg_CallbacksSuccessCursorContinue_Params> params(
404      new IndexedDBMsg_CallbacksSuccessCursorContinue_Params());
405  params->ipc_thread_id = ipc_thread_id_;
406  params->ipc_callbacks_id = ipc_callbacks_id_;
407  params->ipc_cursor_id = ipc_cursor_id_;
408  params->key = key;
409  params->primary_key = primary_key;
410  if (value && !value->empty())
411    std::swap(params->value, value->bits);
412  // TODO(alecflett): Avoid a copy here: the whole params object is
413  // being copied into the message.
414  if (!value || value->blob_info.empty()) {
415    dispatcher_host_->Send(
416        new IndexedDBMsg_CallbacksSuccessCursorContinue(*params));
417  } else {
418    IndexedDBMsg_CallbacksSuccessCursorContinue_Params* p = params.get();
419    FillInBlobData(value->blob_info, &p->blob_or_file_info);
420    RegisterBlobsAndSend(
421        value->blob_info,
422        base::Bind(CreateBlobsAndSend<
423                       IndexedDBMsg_CallbacksSuccessCursorContinue_Params,
424                       IndexedDBMsg_CallbacksSuccessCursorContinue>,
425                   base::Owned(params.release()),
426                   dispatcher_host_,
427                   value->blob_info,
428                   base::Unretained(&p->blob_or_file_info)));
429  }
430  dispatcher_host_ = NULL;
431}
432
433void IndexedDBCallbacks::OnSuccessWithPrefetch(
434    const std::vector<IndexedDBKey>& keys,
435    const std::vector<IndexedDBKey>& primary_keys,
436    std::vector<IndexedDBValue>* values) {
437  DCHECK_EQ(keys.size(), primary_keys.size());
438  DCHECK_EQ(keys.size(), values->size());
439
440  DCHECK(dispatcher_host_.get());
441
442  DCHECK_NE(kNoCursor, ipc_cursor_id_);
443  DCHECK_EQ(kNoTransaction, host_transaction_id_);
444  DCHECK_EQ(kNoDatabase, ipc_database_id_);
445  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
446  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
447
448  std::vector<IndexedDBKey> msgKeys;
449  std::vector<IndexedDBKey> msgPrimaryKeys;
450
451  for (size_t i = 0; i < keys.size(); ++i) {
452    msgKeys.push_back(keys[i]);
453    msgPrimaryKeys.push_back(primary_keys[i]);
454  }
455
456  scoped_ptr<IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params> params(
457      new IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params());
458  params->ipc_thread_id = ipc_thread_id_;
459  params->ipc_callbacks_id = ipc_callbacks_id_;
460  params->ipc_cursor_id = ipc_cursor_id_;
461  params->keys = msgKeys;
462  params->primary_keys = msgPrimaryKeys;
463  std::vector<std::string>& values_bits = params->values;
464  values_bits.resize(values->size());
465  std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >& values_blob_infos =
466      params->blob_or_file_infos;
467  values_blob_infos.resize(values->size());
468
469  bool found_blob_info = false;
470  std::vector<IndexedDBValue>::iterator iter = values->begin();
471  for (size_t i = 0; iter != values->end(); ++iter, ++i) {
472    values_bits[i].swap(iter->bits);
473    if (iter->blob_info.size()) {
474      found_blob_info = true;
475      FillInBlobData(iter->blob_info, &values_blob_infos[i]);
476      std::vector<IndexedDBBlobInfo>::const_iterator blob_iter;
477      for (blob_iter = iter->blob_info.begin();
478           blob_iter != iter->blob_info.end();
479           ++blob_iter) {
480        if (!blob_iter->mark_used_callback().is_null())
481          blob_iter->mark_used_callback().Run();
482      }
483    }
484  }
485
486  if (found_blob_info) {
487    BrowserThread::PostTask(BrowserThread::IO,
488                            FROM_HERE,
489                            base::Bind(BlobLookupForCursorPrefetch,
490                                       base::Owned(params.release()),
491                                       dispatcher_host_,
492                                       *values));
493  } else {
494    dispatcher_host_->Send(
495        new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params.get()));
496  }
497  dispatcher_host_ = NULL;
498}
499
500void IndexedDBCallbacks::OnSuccess(IndexedDBValue* value,
501                                   const IndexedDBKey& key,
502                                   const IndexedDBKeyPath& key_path) {
503  DCHECK(dispatcher_host_.get());
504
505  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
506  DCHECK_EQ(kNoTransaction, host_transaction_id_);
507  DCHECK_EQ(kNoDatabase, ipc_database_id_);
508  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
509  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
510
511  scoped_ptr<IndexedDBMsg_CallbacksSuccessValueWithKey_Params> params(
512      new IndexedDBMsg_CallbacksSuccessValueWithKey_Params());
513  params->ipc_thread_id = ipc_thread_id_;
514  params->ipc_callbacks_id = ipc_callbacks_id_;
515  params->primary_key = key;
516  params->key_path = key_path;
517  if (value && !value->empty())
518    std::swap(params->value, value->bits);
519  if (!value || value->blob_info.empty()) {
520    dispatcher_host_->Send(
521        new IndexedDBMsg_CallbacksSuccessValueWithKey(*params));
522  } else {
523    IndexedDBMsg_CallbacksSuccessValueWithKey_Params* p = params.get();
524    FillInBlobData(value->blob_info, &p->blob_or_file_info);
525    RegisterBlobsAndSend(
526        value->blob_info,
527        base::Bind(
528            CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessValueWithKey_Params,
529                               IndexedDBMsg_CallbacksSuccessValueWithKey>,
530            base::Owned(params.release()),
531            dispatcher_host_,
532            value->blob_info,
533            base::Unretained(&p->blob_or_file_info)));
534  }
535  dispatcher_host_ = NULL;
536}
537
538void IndexedDBCallbacks::OnSuccess(IndexedDBValue* value) {
539  DCHECK(dispatcher_host_.get());
540  DCHECK(kNoCursor == ipc_cursor_id_ || value == NULL);
541  DCHECK_EQ(kNoTransaction, host_transaction_id_);
542  DCHECK_EQ(kNoDatabase, ipc_database_id_);
543  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
544  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
545
546  scoped_ptr<IndexedDBMsg_CallbacksSuccessValue_Params> params(
547      new IndexedDBMsg_CallbacksSuccessValue_Params());
548  params->ipc_thread_id = ipc_thread_id_;
549  params->ipc_callbacks_id = ipc_callbacks_id_;
550  if (value && !value->empty())
551    std::swap(params->value, value->bits);
552  if (!value || value->blob_info.empty()) {
553    dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessValue(*params));
554  } else {
555    IndexedDBMsg_CallbacksSuccessValue_Params* p = params.get();
556    FillInBlobData(value->blob_info, &p->blob_or_file_info);
557    RegisterBlobsAndSend(
558        value->blob_info,
559        base::Bind(CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessValue_Params,
560                                      IndexedDBMsg_CallbacksSuccessValue>,
561                   base::Owned(params.release()),
562                   dispatcher_host_,
563                   value->blob_info,
564                   base::Unretained(&p->blob_or_file_info)));
565  }
566  dispatcher_host_ = NULL;
567}
568
569void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& value) {
570  DCHECK(dispatcher_host_.get());
571
572  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
573  DCHECK_EQ(kNoTransaction, host_transaction_id_);
574  DCHECK_EQ(kNoDatabase, ipc_database_id_);
575  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
576  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
577
578  dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessIndexedDBKey(
579      ipc_thread_id_, ipc_callbacks_id_, value));
580  dispatcher_host_ = NULL;
581}
582
583void IndexedDBCallbacks::OnSuccess(int64 value) {
584  DCHECK(dispatcher_host_.get());
585
586  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
587  DCHECK_EQ(kNoTransaction, host_transaction_id_);
588  DCHECK_EQ(kNoDatabase, ipc_database_id_);
589  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
590  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
591
592  dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessInteger(
593      ipc_thread_id_, ipc_callbacks_id_, value));
594  dispatcher_host_ = NULL;
595}
596
597void IndexedDBCallbacks::OnSuccess() {
598  DCHECK(dispatcher_host_.get());
599
600  DCHECK_EQ(kNoCursor, ipc_cursor_id_);
601  DCHECK_EQ(kNoTransaction, host_transaction_id_);
602  DCHECK_EQ(kNoDatabase, ipc_database_id_);
603  DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
604  DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
605
606  dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessUndefined(
607      ipc_thread_id_, ipc_callbacks_id_));
608  dispatcher_host_ = NULL;
609}
610
611void IndexedDBCallbacks::SetConnectionOpenStartTime(
612    const base::TimeTicks& start_time) {
613  connection_open_start_time_ = start_time;
614}
615
616}  // namespace content
617