Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / indexed_db / indexed_db_callbacks.cc
index 6547fdd..74c2558 100644 (file)
@@ -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"
 #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,128 @@ 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) {
+  std::string uuid = blob_info.uuid();
+  if (!uuid.empty()) {
+    // We're sending back a live blob, not a reference into our backing store.
+    scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle(
+        blob_storage_context->GetBlobDataFromUUID(uuid));
+    dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle);
+    return uuid;
+  }
+  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);
+    if (!blob_info.release_callback().is_null())
+      shareable_file->AddFinalReleaseCallback(blob_info.release_callback());
+  }
+
+  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();
+      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) {
+    if (!iter->mark_used_callback().is_null())
+      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 +316,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 +362,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 +416,49 @@ 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) {
+        if (!blob_iter->mark_used_callback().is_null())
+          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(&params->blob_or_file_infos)));
+  } else {
+    dispatcher_host_->Send(
+        new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params.get()));
+  }
   dispatcher_host_ = NULL;
 }
 
@@ -277,38 +473,61 @@ void IndexedDBCallbacks::OnSuccess(IndexedDBValue* value,
   DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
   DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
 
-  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->bits);
-
-  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 || 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_);
 
-  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->bits);
-
-  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 || 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;
 }