Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Unified Diff: content/browser/indexed_db/indexed_db_callbacks.cc

Issue 18023022: Blob support for IDB [Chromium] (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge fixes [builds, untested] Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 46270db75311620877979a1bec17e1464fc9b51e..3a16ee35b838a1ca4906108ec12f5dee8aa44b3d 100644
--- a/content/browser/indexed_db/indexed_db_callbacks.cc
+++ b/content/browser/indexed_db/indexed_db_callbacks.cc
@@ -6,15 +6,25 @@
#include <algorithm>
+#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"
#include "content/browser/indexed_db/indexed_db_metadata.h"
+#include "content/browser/indexed_db/indexed_db_value.h"
#include "content/common/indexed_db/indexed_db_messages.h"
#include "webkit/browser/quota/quota_manager.h"
+#include "webkit/common/blob/blob_data.h"
+#include "webkit/common/blob/shareable_file_reference.cc"
using WebKit::WebIDBCallbacks;
+using webkit_blob::ShareableFileReference;
namespace content {
@@ -158,10 +168,177 @@ void IndexedDBCallbacks::OnSuccess(scoped_ptr<IndexedDBConnection> connection,
dispatcher_host_ = NULL;
}
+// Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+// TODO: Remove this.
+static std::string MakeFakeGuid() {
+ static int32 counter = 0;
+ return base::StringPrintf("00000000-0000-4000-8000-0000%08x", counter++);
+}
+
+// TODO: Remove this when Michael gives us a better way to do it.
+static GURL CreateBlob(
+ const IndexedDBBlobInfo& blob_info,
+ FileAPIMessageFilter* file_api_message_filter,
+ 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 blob_uuid(MakeFakeGuid());
+ GURL blob_url("blob:blobinternal%a///" + MakeFakeGuid());
+ webkit_blob::BlobData::Item item;
+ item.SetToFilePath(blob_info.file_path());
+
+ // It would be much nicer not to go through the FileAPIMessageFilter here, but
+ // if we go around it, it doesn't know about the blob we create, and can't
+ // free it later when the renderer exits.
+ file_api_message_filter->OnStartBuildingBlob(blob_uuid);
+ file_api_message_filter->OnAppendBlobDataItemToBlob(blob_uuid, item);
+ file_api_message_filter->OnFinishBuildingBlob(blob_uuid,
+ base::UTF16ToUTF8(blob_info.type()));
+ file_api_message_filter->OnDeprecatedRegisterBlobURL(blob_url, blob_uuid);
+ // We've just added an extra refcount for blob_uuid that will never be cleaned
+ // up. We should remove it as soon as the blob gets cloned by the renderer,
+ // but we have no way of knowing when that's happened. So for now I put in
+ // this huge HACK to do a delayed decrement after what should be a safe delay
+ // in most cases.
+ if (!BrowserThread::PostDelayedTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&FileAPIMessageFilter::OnDeprecatedRevokeBlobURL,
+ file_api_message_filter, blob_url), base::TimeDelta::FromSeconds(10))) {
+ fprintf(stderr, "ERICU: We're going to leak a blob.\n");
+ }
+ return blob_url;
+}
+
+static void CreateAllBlobs(
+ const std::vector<IndexedDBBlobInfo>& blob_info,
+ std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info,
+ FileAPIMessageFilter* file_api_message_filter,
+ base::TaskRunner* task_runner) {
+ size_t i;
+ for (i = 0; i < blob_info.size(); ++i) {
+ (*blob_or_file_info)[i].url =
+ CreateBlob(blob_info[i], file_api_message_filter, task_runner);
+ }
+}
+
+static void BlobLookupForIDBCursor(
+ IndexedDBMsg_CallbacksSuccessIDBCursor_Params* 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));
+ CreateAllBlobs(blob_info, blob_or_file_info,
+ dispatcher_host->file_api_message_filter(),
+ dispatcher_host->Context()->TaskRunner());
+ dispatcher_host->Send(
+ new IndexedDBMsg_CallbacksSuccessIDBCursor(*params));
+}
+
+static void BlobLookupForCursorContinue(
+ IndexedDBMsg_CallbacksSuccessCursorContinue_Params* 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));
+ CreateAllBlobs(blob_info, blob_or_file_info,
+ dispatcher_host->file_api_message_filter(),
+ dispatcher_host->Context()->TaskRunner());
+ dispatcher_host->Send(
+ new IndexedDBMsg_CallbacksSuccessCursorContinue(*params));
+}
+
+static void BlobLookupForValueWithKey(
+ IndexedDBMsg_CallbacksSuccessValueWithKey_Params* 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));
+ CreateAllBlobs(blob_info, blob_or_file_info,
+ dispatcher_host->file_api_message_filter(),
+ dispatcher_host->Context()->TaskRunner());
+ dispatcher_host->Send(
+ new IndexedDBMsg_CallbacksSuccessValueWithKey(*params));
+}
+
+static void BlobLookupForValue(
+ IndexedDBMsg_CallbacksSuccessValue_Params* 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));
+ CreateAllBlobs(blob_info, blob_or_file_info,
+ dispatcher_host->file_api_message_filter(),
+ dispatcher_host->Context()->TaskRunner());
+ dispatcher_host->Send(new IndexedDBMsg_CallbacksSuccessValue(*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(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) {
+ CreateAllBlobs(value_iter->blob_info, &*blob_iter,
+ dispatcher_host->file_api_message_filter(),
+ dispatcher_host->Context()->TaskRunner());
+ }
+ 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,
- std::string* value) {
+ IndexedDBValue* value) {
DCHECK(dispatcher_host_.get());
DCHECK_EQ(kNoCursor, ipc_cursor_id_);
@@ -170,24 +347,34 @@ void IndexedDBCallbacks::OnSuccess(scoped_refptr<IndexedDBCursor> cursor,
DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
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);
+ 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->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(BlobLookupForIDBCursor, base::Owned(params.release()),
+ dispatcher_host_, value->blob_info,
+ base::Unretained(&p->blob_or_file_info)));
+ }
dispatcher_host_ = NULL;
}
void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& key,
const IndexedDBKey& primary_key,
- std::string* value) {
+ IndexedDBValue* value) {
DCHECK(dispatcher_host_.get());
DCHECK_NE(kNoCursor, ipc_cursor_id_);
@@ -201,25 +388,37 @@ 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);
+ 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->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(BlobLookupForCursorContinue, 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<std::string>& values) {
+ std::vector<IndexedDBValue>& values) {
DCHECK_EQ(keys.size(), primary_keys.size());
DCHECK_EQ(keys.size(), values.size());
@@ -238,19 +437,47 @@ 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;
- params.values = values;
- 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(values.size());
+ std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >
+ values_blob_infos(values.size());
+ std::vector<IndexedDBValue>::iterator iter = values.begin();
+
+ bool found_blob_info = false;
+ 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();
+ }
+ }
+ }
+
+ params->values.swap(values_bits);
+ if (found_blob_info) {
+ params->blob_or_file_infos.swap(values_blob_infos);
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(BlobLookupForCursorPrefetch, base::Owned(params.release()),
+ dispatcher_host_, values,
+ base::Unretained(&params->blob_or_file_infos)));
+ } else {
+ dispatcher_host_->Send(
+ new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params.get()));
+ }
dispatcher_host_ = NULL;
}
-void IndexedDBCallbacks::OnSuccess(std::string* value,
+void IndexedDBCallbacks::OnSuccess(IndexedDBValue* value,
const IndexedDBKey& key,
const IndexedDBKeyPath& key_path) {
DCHECK(dispatcher_host_.get());
@@ -260,37 +487,54 @@ void IndexedDBCallbacks::OnSuccess(std::string* value,
DCHECK_EQ(kNoDatabase, ipc_database_id_);
DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
- std::string value_copy;
+ 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(value_copy, *value);
-
- dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessValueWithKey(
- ipc_thread_id_,
- ipc_callbacks_id_,
- // TODO(alecflett): Avoid a copy here.
- value_copy,
- key,
- key_path));
+ std::swap(params->value, value->bits);
+ if (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(BlobLookupForValueWithKey, base::Owned(params.release()),
+ dispatcher_host_, value->blob_info,
+ base::Unretained(&p->blob_or_file_info)));
+ }
dispatcher_host_ = NULL;
}
-void IndexedDBCallbacks::OnSuccess(std::string* value) {
+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_);
- std::string value_copy;
+ 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(value_copy, *value);
-
- dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessValue(
- ipc_thread_id_,
- ipc_callbacks_id_,
- // TODO(alecflett): avoid a copy here.
- value_copy));
+ std::swap(params->value, value->bits);
+ if (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(BlobLookupForValue, base::Owned(params.release()),
+ dispatcher_host_, value->blob_info,
+ base::Unretained(&p->blob_or_file_info)));
+ }
dispatcher_host_ = NULL;
}

Powered by Google App Engine
This is Rietveld 408576698