| Index: content/browser/indexed_db/indexed_db_callbacks.cc
|
| diff --git a/content/browser/indexed_db/indexed_db_callbacks.cc b/content/browser/indexed_db/indexed_db_callbacks.cc
|
| index f4c348765b3495e32af1580d0b84e330629131c8..ad5551f388417da4d261297fc6fa0111183b034b 100644
|
| --- a/content/browser/indexed_db/indexed_db_callbacks.cc
|
| +++ b/content/browser/indexed_db/indexed_db_callbacks.cc
|
| @@ -6,7 +6,14 @@
|
|
|
| #include <algorithm>
|
|
|
| +#include "base/guid.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "base/time/time.h"
|
| +#include "content/browser/child_process_security_policy_impl.h"
|
| +#include "content/browser/fileapi/fileapi_message_filter.h"
|
| +#include "content/browser/indexed_db/indexed_db_blob_info.h"
|
| #include "content/browser/indexed_db/indexed_db_connection.h"
|
| +#include "content/browser/indexed_db/indexed_db_context_impl.h"
|
| #include "content/browser/indexed_db/indexed_db_cursor.h"
|
| #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
|
| #include "content/browser/indexed_db/indexed_db_database_error.h"
|
| @@ -14,7 +21,12 @@
|
| #include "content/browser/indexed_db/indexed_db_value.h"
|
| #include "content/common/indexed_db/indexed_db_constants.h"
|
| #include "content/common/indexed_db/indexed_db_messages.h"
|
| +#include "webkit/browser/blob/blob_storage_context.h"
|
| #include "webkit/browser/quota/quota_manager.h"
|
| +#include "webkit/common/blob/blob_data.h"
|
| +#include "webkit/common/blob/shareable_file_reference.h"
|
| +
|
| +using webkit_blob::ShareableFileReference;
|
|
|
| namespace content {
|
|
|
| @@ -169,6 +181,119 @@ void IndexedDBCallbacks::OnSuccess(scoped_ptr<IndexedDBConnection> connection,
|
| dispatcher_host_ = NULL;
|
| }
|
|
|
| +static std::string CreateBlobData(
|
| + const IndexedDBBlobInfo& blob_info,
|
| + scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
|
| + webkit_blob::BlobStorageContext* blob_storage_context,
|
| + base::TaskRunner* task_runner) {
|
| + scoped_refptr<ShareableFileReference> shareable_file =
|
| + ShareableFileReference::Get(blob_info.file_path());
|
| + if (!shareable_file.get()) {
|
| + shareable_file = ShareableFileReference::GetOrCreate(
|
| + blob_info.file_path(),
|
| + ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
|
| + task_runner);
|
| + shareable_file->AddFinalReleaseCallback(blob_info.release_callback());
|
| + }
|
| +
|
| + std::string uuid(base::GenerateGUID());
|
| + scoped_refptr<webkit_blob::BlobData> blob_data =
|
| + new webkit_blob::BlobData(uuid);
|
| + blob_data->AppendFile(
|
| + blob_info.file_path(), 0, blob_info.size(), blob_info.last_modified());
|
| + scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle(
|
| + blob_storage_context->AddFinishedBlob(blob_data.get()));
|
| + dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle);
|
| +
|
| + return uuid;
|
| +}
|
| +
|
| +static bool CreateAllBlobs(
|
| + const std::vector<IndexedDBBlobInfo>& blob_info,
|
| + std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info,
|
| + scoped_refptr<IndexedDBDispatcherHost> dispatcher_host) {
|
| + DCHECK_EQ(blob_info.size(), blob_or_file_info->size());
|
| + size_t i;
|
| + if (!dispatcher_host->blob_storage_context())
|
| + return false;
|
| + for (i = 0; i < blob_info.size(); ++i) {
|
| + (*blob_or_file_info)[i].uuid =
|
| + CreateBlobData(blob_info[i],
|
| + dispatcher_host,
|
| + dispatcher_host->blob_storage_context(),
|
| + dispatcher_host->Context()->TaskRunner());
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +template <class ParamType, class MsgType>
|
| +static void CreateBlobsAndSend(
|
| + ParamType* params,
|
| + scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
|
| + const std::vector<IndexedDBBlobInfo>& blob_info,
|
| + std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + if (CreateAllBlobs(blob_info, blob_or_file_info, dispatcher_host))
|
| + dispatcher_host->Send(new MsgType(*params));
|
| +}
|
| +
|
| +static void BlobLookupForCursorPrefetch(
|
| + IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params* params,
|
| + scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
|
| + const std::vector<IndexedDBValue>& values,
|
| + std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >*
|
| + blob_or_file_infos) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + DCHECK_EQ(values.size(), blob_or_file_infos->size());
|
| +
|
| + std::vector<IndexedDBValue>::const_iterator value_iter;
|
| + std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >::iterator blob_iter;
|
| + for (value_iter = values.begin(), blob_iter = blob_or_file_infos->begin();
|
| + value_iter != values.end();
|
| + ++value_iter, ++blob_iter) {
|
| + if (!CreateAllBlobs(value_iter->blob_info, &*blob_iter, dispatcher_host))
|
| + return;
|
| + }
|
| + dispatcher_host->Send(
|
| + new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params));
|
| +}
|
| +
|
| +static void FillInBlobData(
|
| + const std::vector<IndexedDBBlobInfo>& blob_info,
|
| + std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info) {
|
| + for (std::vector<IndexedDBBlobInfo>::const_iterator iter = blob_info.begin();
|
| + iter != blob_info.end();
|
| + ++iter) {
|
| + if (iter->is_file()) {
|
| + IndexedDBMsg_BlobOrFileInfo info;
|
| + info.is_file = true;
|
| + info.mime_type = iter->type();
|
| + info.file_name = iter->file_name();
|
| + info.file_path = iter->file_path().AsUTF16Unsafe();
|
| + DCHECK_NE(-1, iter->size());
|
| + info.size = iter->size();
|
| + info.last_modified = iter->last_modified().ToDoubleT();
|
| + blob_or_file_info->push_back(info);
|
| + } else {
|
| + IndexedDBMsg_BlobOrFileInfo info;
|
| + info.mime_type = iter->type();
|
| + info.size = iter->size();
|
| + blob_or_file_info->push_back(info);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void IndexedDBCallbacks::RegisterBlobsAndSend(
|
| + const std::vector<IndexedDBBlobInfo>& blob_info,
|
| + const base::Closure& callback) {
|
| + std::vector<IndexedDBBlobInfo>::const_iterator iter;
|
| + for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) {
|
| + iter->mark_used_callback().Run();
|
| + }
|
| + DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback);
|
| +}
|
| +
|
| void IndexedDBCallbacks::OnSuccess(scoped_refptr<IndexedDBCursor> cursor,
|
| const IndexedDBKey& key,
|
| const IndexedDBKey& primary_key,
|
| @@ -182,18 +307,32 @@ void IndexedDBCallbacks::OnSuccess(scoped_refptr<IndexedDBCursor> cursor,
|
| DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
|
|
|
| int32 ipc_object_id = dispatcher_host_->Add(cursor.get());
|
| - IndexedDBMsg_CallbacksSuccessIDBCursor_Params params;
|
| - params.ipc_thread_id = ipc_thread_id_;
|
| - params.ipc_callbacks_id = ipc_callbacks_id_;
|
| - params.ipc_cursor_id = ipc_object_id;
|
| - params.key = key;
|
| - params.primary_key = primary_key;
|
| + scoped_ptr<IndexedDBMsg_CallbacksSuccessIDBCursor_Params> params(
|
| + new IndexedDBMsg_CallbacksSuccessIDBCursor_Params());
|
| + params->ipc_thread_id = ipc_thread_id_;
|
| + params->ipc_callbacks_id = ipc_callbacks_id_;
|
| + params->ipc_cursor_id = ipc_object_id;
|
| + params->key = key;
|
| + params->primary_key = primary_key;
|
| if (value && !value->empty())
|
| - std::swap(params.value, value->bits);
|
| + std::swap(params->value, value->bits);
|
| // TODO(alecflett): Avoid a copy here: the whole params object is
|
| // being copied into the message.
|
| - dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessIDBCursor(params));
|
| -
|
| + if (!value || value->blob_info.empty()) {
|
| + dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessIDBCursor(*params));
|
| + } else {
|
| + IndexedDBMsg_CallbacksSuccessIDBCursor_Params* p = params.get();
|
| + FillInBlobData(value->blob_info, &p->blob_or_file_info);
|
| + RegisterBlobsAndSend(
|
| + value->blob_info,
|
| + base::Bind(
|
| + CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessIDBCursor_Params,
|
| + IndexedDBMsg_CallbacksSuccessIDBCursor>,
|
| + base::Owned(params.release()),
|
| + dispatcher_host_,
|
| + value->blob_info,
|
| + base::Unretained(&p->blob_or_file_info)));
|
| + }
|
| dispatcher_host_ = NULL;
|
| }
|
|
|
| @@ -214,25 +353,41 @@ void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& key,
|
| DCHECK(idb_cursor);
|
| if (!idb_cursor)
|
| return;
|
| - IndexedDBMsg_CallbacksSuccessCursorContinue_Params params;
|
| - params.ipc_thread_id = ipc_thread_id_;
|
| - params.ipc_callbacks_id = ipc_callbacks_id_;
|
| - params.ipc_cursor_id = ipc_cursor_id_;
|
| - params.key = key;
|
| - params.primary_key = primary_key;
|
| +
|
| + scoped_ptr<IndexedDBMsg_CallbacksSuccessCursorContinue_Params> params(
|
| + new IndexedDBMsg_CallbacksSuccessCursorContinue_Params());
|
| + params->ipc_thread_id = ipc_thread_id_;
|
| + params->ipc_callbacks_id = ipc_callbacks_id_;
|
| + params->ipc_cursor_id = ipc_cursor_id_;
|
| + params->key = key;
|
| + params->primary_key = primary_key;
|
| if (value && !value->empty())
|
| - std::swap(params.value, value->bits);
|
| + std::swap(params->value, value->bits);
|
| // TODO(alecflett): Avoid a copy here: the whole params object is
|
| // being copied into the message.
|
| - dispatcher_host_->Send(
|
| - new IndexedDBMsg_CallbacksSuccessCursorContinue(params));
|
| + if (!value || value->blob_info.empty()) {
|
| + dispatcher_host_->Send(
|
| + new IndexedDBMsg_CallbacksSuccessCursorContinue(*params));
|
| + } else {
|
| + IndexedDBMsg_CallbacksSuccessCursorContinue_Params* p = params.get();
|
| + FillInBlobData(value->blob_info, &p->blob_or_file_info);
|
| + RegisterBlobsAndSend(
|
| + value->blob_info,
|
| + base::Bind(CreateBlobsAndSend<
|
| + IndexedDBMsg_CallbacksSuccessCursorContinue_Params,
|
| + IndexedDBMsg_CallbacksSuccessCursorContinue>,
|
| + base::Owned(params.release()),
|
| + dispatcher_host_,
|
| + value->blob_info,
|
| + base::Unretained(&p->blob_or_file_info)));
|
| + }
|
| dispatcher_host_ = NULL;
|
| }
|
|
|
| void IndexedDBCallbacks::OnSuccessWithPrefetch(
|
| const std::vector<IndexedDBKey>& keys,
|
| const std::vector<IndexedDBKey>& primary_keys,
|
| - const std::vector<IndexedDBValue>& values) {
|
| + std::vector<IndexedDBValue>& values) {
|
| DCHECK_EQ(keys.size(), primary_keys.size());
|
| DCHECK_EQ(keys.size(), values.size());
|
|
|
| @@ -252,17 +407,48 @@ void IndexedDBCallbacks::OnSuccessWithPrefetch(
|
| msgPrimaryKeys.push_back(primary_keys[i]);
|
| }
|
|
|
| - IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params params;
|
| - params.ipc_thread_id = ipc_thread_id_;
|
| - params.ipc_callbacks_id = ipc_callbacks_id_;
|
| - params.ipc_cursor_id = ipc_cursor_id_;
|
| - params.keys = msgKeys;
|
| - params.primary_keys = msgPrimaryKeys;
|
| - std::vector<IndexedDBValue>::const_iterator iter;
|
| - for (iter = values.begin(); iter != values.end(); ++iter)
|
| - params.values.push_back(iter->bits);
|
| - dispatcher_host_->Send(
|
| - new IndexedDBMsg_CallbacksSuccessCursorPrefetch(params));
|
| + scoped_ptr<IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params> params(
|
| + new IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params());
|
| + params->ipc_thread_id = ipc_thread_id_;
|
| + params->ipc_callbacks_id = ipc_callbacks_id_;
|
| + params->ipc_cursor_id = ipc_cursor_id_;
|
| + params->keys = msgKeys;
|
| + params->primary_keys = msgPrimaryKeys;
|
| + std::vector<std::string>& values_bits = params->values;
|
| + values_bits.resize(values.size());
|
| + std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >& values_blob_infos =
|
| + params->blob_or_file_infos;
|
| + values_blob_infos.resize(values.size());
|
| +
|
| + bool found_blob_info = false;
|
| + std::vector<IndexedDBValue>::iterator iter = values.begin();
|
| + for (size_t i = 0; iter != values.end(); ++iter, ++i) {
|
| + values_bits[i].swap(iter->bits);
|
| + if (iter->blob_info.size()) {
|
| + found_blob_info = true;
|
| + FillInBlobData(iter->blob_info, &values_blob_infos[i]);
|
| + std::vector<IndexedDBBlobInfo>::const_iterator blob_iter;
|
| + for (blob_iter = iter->blob_info.begin();
|
| + blob_iter != iter->blob_info.end();
|
| + ++blob_iter) {
|
| + blob_iter->mark_used_callback().Run();
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (found_blob_info) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(BlobLookupForCursorPrefetch,
|
| + base::Owned(params.release()),
|
| + dispatcher_host_,
|
| + values,
|
| + base::Unretained(¶ms->blob_or_file_infos)));
|
| + } else {
|
| + dispatcher_host_->Send(
|
| + new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params.get()));
|
| + }
|
| dispatcher_host_ = NULL;
|
| }
|
|
|
| @@ -277,34 +463,61 @@ void IndexedDBCallbacks::OnSuccess(IndexedDBValue* value,
|
| DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
|
| DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
|
|
|
| - IndexedDBMsg_CallbacksSuccessValueWithKey_Params params;
|
| - params.ipc_thread_id = ipc_thread_id_;
|
| - params.ipc_callbacks_id = ipc_callbacks_id_;
|
| - params.primary_key = key;
|
| - params.key_path = key_path;
|
| + scoped_ptr<IndexedDBMsg_CallbacksSuccessValueWithKey_Params> params(
|
| + new IndexedDBMsg_CallbacksSuccessValueWithKey_Params());
|
| + params->ipc_thread_id = ipc_thread_id_;
|
| + params->ipc_callbacks_id = ipc_callbacks_id_;
|
| + params->primary_key = key;
|
| + params->key_path = key_path;
|
| if (value && !value->empty())
|
| - std::swap(params.value, value->bits);
|
| -
|
| - dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessValueWithKey(params));
|
| + std::swap(params->value, value->bits);
|
| + if (!value || value->blob_info.empty()) {
|
| + dispatcher_host_->Send(
|
| + new IndexedDBMsg_CallbacksSuccessValueWithKey(*params));
|
| + } else {
|
| + IndexedDBMsg_CallbacksSuccessValueWithKey_Params* p = params.get();
|
| + FillInBlobData(value->blob_info, &p->blob_or_file_info);
|
| + RegisterBlobsAndSend(
|
| + value->blob_info,
|
| + base::Bind(
|
| + CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessValueWithKey_Params,
|
| + IndexedDBMsg_CallbacksSuccessValueWithKey>,
|
| + base::Owned(params.release()),
|
| + dispatcher_host_,
|
| + value->blob_info,
|
| + base::Unretained(&p->blob_or_file_info)));
|
| + }
|
| dispatcher_host_ = NULL;
|
| }
|
|
|
| void IndexedDBCallbacks::OnSuccess(IndexedDBValue* value) {
|
| DCHECK(dispatcher_host_.get());
|
| -
|
| DCHECK(kNoCursor == ipc_cursor_id_ || value == NULL);
|
| DCHECK_EQ(kNoTransaction, host_transaction_id_);
|
| DCHECK_EQ(kNoDatabase, ipc_database_id_);
|
| DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
|
| DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
|
|
|
| - IndexedDBMsg_CallbacksSuccessValue_Params params;
|
| - params.ipc_thread_id = ipc_thread_id_;
|
| - params.ipc_callbacks_id = ipc_callbacks_id_;
|
| + scoped_ptr<IndexedDBMsg_CallbacksSuccessValue_Params> params(
|
| + new IndexedDBMsg_CallbacksSuccessValue_Params());
|
| + params->ipc_thread_id = ipc_thread_id_;
|
| + params->ipc_callbacks_id = ipc_callbacks_id_;
|
| if (value && !value->empty())
|
| - std::swap(params.value, value->bits);
|
| -
|
| - dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessValue(params));
|
| + std::swap(params->value, value->bits);
|
| + if (!value || value->blob_info.empty()) {
|
| + dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessValue(*params));
|
| + } else {
|
| + IndexedDBMsg_CallbacksSuccessValue_Params* p = params.get();
|
| + FillInBlobData(value->blob_info, &p->blob_or_file_info);
|
| + RegisterBlobsAndSend(
|
| + value->blob_info,
|
| + base::Bind(CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessValue_Params,
|
| + IndexedDBMsg_CallbacksSuccessValue>,
|
| + base::Owned(params.release()),
|
| + dispatcher_host_,
|
| + value->blob_info,
|
| + base::Unretained(&p->blob_or_file_info)));
|
| + }
|
| dispatcher_host_ = NULL;
|
| }
|
|
|
|
|