Index: content/child/webblobregistry_impl.cc |
diff --git a/content/child/webblobregistry_impl.cc b/content/child/webblobregistry_impl.cc |
index 22f6f43acdc25c351b2e70b575a56bc04540d2a4..1967c7b151a0e551cf6d0cddb17c1ff5ef0567aa 100644 |
--- a/content/child/webblobregistry_impl.cc |
+++ b/content/child/webblobregistry_impl.cc |
@@ -7,6 +7,7 @@ |
#include "base/files/file_path.h" |
#include "base/guid.h" |
#include "base/memory/ref_counted.h" |
+#include "base/memory/scoped_ptr.h" |
#include "base/memory/shared_memory.h" |
#include "base/message_loop/message_loop.h" |
#include "base/trace_event/trace_event.h" |
@@ -22,6 +23,8 @@ using blink::WebBlobData; |
using blink::WebString; |
using blink::WebThreadSafeData; |
using blink::WebURL; |
+using blink::WebBlobRegistry; |
+using storage::DataElement; |
namespace content { |
@@ -42,79 +45,55 @@ WebBlobRegistryImpl::WebBlobRegistryImpl(ThreadSafeSender* sender) |
WebBlobRegistryImpl::~WebBlobRegistryImpl() { |
} |
-void WebBlobRegistryImpl::registerBlobData( |
- const blink::WebString& uuid, const blink::WebBlobData& data) { |
- TRACE_EVENT0("Blob", "Registry::RegisterBlob"); |
- const std::string uuid_str(uuid.utf8()); |
+blink::WebBlobRegistry::Builder* WebBlobRegistryImpl::createBuilder( |
+ const blink::WebString& uuid, |
+ const blink::WebString& contentType) { |
+ return new BuilderImpl(uuid, contentType, sender_.get()); |
+} |
- storage::DataElement data_buffer; |
- data_buffer.SetToEmptyBytes(); |
+void WebBlobRegistryImpl::registerBlobData(const blink::WebString& uuid, |
+ const blink::WebBlobData& data) { |
+ TRACE_EVENT0("Blob", "Registry::RegisterBlob"); |
+ scoped_ptr<Builder> builder(createBuilder(uuid, data.contentType())); |
- sender_->Send(new BlobHostMsg_StartBuilding(uuid_str)); |
+ // This is temporary until we move to createBuilder() as our blob creation |
+ // method. |
size_t i = 0; |
WebBlobData::Item data_item; |
while (data.itemAt(i++, data_item)) { |
- // NOTE: data_item.length == -1 when we want to use the whole file. This |
- // only happens when we are creating a file object in Blink, and the file |
- // object is the only item in the 'blob'. If we use that file blob to |
- // create another blob, it is sent here as a 'file' item and not a blob, |
- // and the correct size is populated. |
- // static_cast<uint64>(-1) == kuint64max, which is what DataElement uses |
- // to specificy "use the whole file". |
if (data_item.length == 0) { |
continue; |
} |
- if (data_item.type != WebBlobData::Item::TypeData && |
- data_buffer.length() != 0) { |
- FlushBlobItemBuffer(uuid_str, &data_buffer); |
- } |
- storage::DataElement item; |
switch (data_item.type) { |
case WebBlobData::Item::TypeData: { |
// WebBlobData does not allow partial data items. |
DCHECK(!data_item.offset && data_item.length == -1); |
- if (data_item.data.size() == 0) { |
- continue; |
- } |
- BufferBlobData(uuid_str, data_item.data, &data_buffer); |
+ builder->appendData(data_item.data); |
break; |
} |
case WebBlobData::Item::TypeFile: |
- item.SetToFilePathRange( |
- base::FilePath::FromUTF16Unsafe(data_item.filePath), |
- static_cast<uint64>(data_item.offset), |
- static_cast<uint64>(data_item.length), |
- base::Time::FromDoubleT(data_item.expectedModificationTime)); |
- sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str, item)); |
+ builder->appendFile(data_item.filePath, |
+ static_cast<uint64_t>(data_item.offset), |
+ static_cast<uint64_t>(data_item.length), |
+ data_item.expectedModificationTime); |
break; |
case WebBlobData::Item::TypeBlob: |
- item.SetToBlobRange( |
- data_item.blobUUID.utf8(), |
- static_cast<uint64>(data_item.offset), |
- static_cast<uint64>(data_item.length)); |
- sender_->Send( |
- new BlobHostMsg_AppendBlobDataItem(uuid_str, item)); |
+ builder->appendBlob(data_item.blobUUID, data_item.offset, |
+ data_item.length); |
break; |
case WebBlobData::Item::TypeFileSystemURL: |
// We only support filesystem URL as of now. |
DCHECK(GURL(data_item.fileSystemURL).SchemeIsFileSystem()); |
- item.SetToFileSystemUrlRange( |
- data_item.fileSystemURL, |
- static_cast<uint64>(data_item.offset), |
- static_cast<uint64>(data_item.length), |
- base::Time::FromDoubleT(data_item.expectedModificationTime)); |
- sender_->Send( |
- new BlobHostMsg_AppendBlobDataItem(uuid_str, item)); |
+ builder->appendFileSystemURL(data_item.fileSystemURL, |
+ static_cast<uint64>(data_item.offset), |
+ static_cast<uint64>(data_item.length), |
+ data_item.expectedModificationTime); |
break; |
default: |
NOTREACHED(); |
} |
} |
- if (data_buffer.length() != 0) { |
- FlushBlobItemBuffer(uuid_str, &data_buffer); |
- } |
- sender_->Send(new BlobHostMsg_FinishBuilding( |
- uuid_str, data.contentType().utf8().data())); |
+ builder->build(); |
} |
void WebBlobRegistryImpl::addBlobDataRef(const WebString& uuid) { |
@@ -125,8 +104,8 @@ void WebBlobRegistryImpl::removeBlobDataRef(const WebString& uuid) { |
sender_->Send(new BlobHostMsg_DecrementRefCount(uuid.utf8())); |
} |
-void WebBlobRegistryImpl::registerPublicBlobURL( |
- const WebURL& url, const WebString& uuid) { |
+void WebBlobRegistryImpl::registerPublicBlobURL(const WebURL& url, |
+ const WebString& uuid) { |
sender_->Send(new BlobHostMsg_RegisterPublicURL(url, uuid.utf8())); |
} |
@@ -134,88 +113,34 @@ void WebBlobRegistryImpl::revokePublicBlobURL(const WebURL& url) { |
sender_->Send(new BlobHostMsg_RevokePublicURL(url)); |
} |
-void WebBlobRegistryImpl::FlushBlobItemBuffer( |
- const std::string& uuid_str, |
- storage::DataElement* data_buffer) const { |
- DCHECK_NE(data_buffer->length(), 0ul); |
- DCHECK_LT(data_buffer->length(), kLargeThresholdBytes); |
- sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str, *data_buffer)); |
- data_buffer->SetToEmptyBytes(); |
-} |
- |
-void WebBlobRegistryImpl::BufferBlobData(const std::string& uuid_str, |
- const blink::WebThreadSafeData& data, |
- storage::DataElement* data_buffer) { |
- size_t buffer_size = data_buffer->length(); |
- size_t data_size = data.size(); |
- DCHECK_NE(data_size, 0ul); |
- if (buffer_size != 0 && buffer_size + data_size >= kLargeThresholdBytes) { |
- FlushBlobItemBuffer(uuid_str, data_buffer); |
- buffer_size = 0; |
- } |
- if (data_size >= kLargeThresholdBytes) { |
- TRACE_EVENT0("Blob", "Registry::SendOversizedBlobData"); |
- SendOversizedDataForBlob(uuid_str, data); |
- } else { |
- DCHECK_LT(buffer_size + data_size, kLargeThresholdBytes); |
- data_buffer->AppendBytes(data.data(), data_size); |
- } |
-} |
- |
-void WebBlobRegistryImpl::SendOversizedDataForBlob( |
- const std::string& uuid_str, |
- const blink::WebThreadSafeData& data) { |
- DCHECK_GE(data.size(), kLargeThresholdBytes); |
- // We handle larger amounts of data via SharedMemory instead of |
- // writing it directly to the IPC channel. |
- size_t shared_memory_size = std::min(data.size(), kMaxSharedMemoryBytes); |
- scoped_ptr<base::SharedMemory> shared_memory( |
- ChildThreadImpl::AllocateSharedMemory(shared_memory_size, sender_.get())); |
- CHECK(shared_memory.get()); |
- if (!shared_memory->Map(shared_memory_size)) |
- CHECK(false); |
- |
- size_t data_size = data.size(); |
- const char* data_ptr = data.data(); |
- while (data_size) { |
- TRACE_EVENT0("Blob", "Registry::SendOversizedBlobItem"); |
- size_t chunk_size = std::min(data_size, shared_memory_size); |
- memcpy(shared_memory->memory(), data_ptr, chunk_size); |
- sender_->Send(new BlobHostMsg_SyncAppendSharedMemory( |
- uuid_str, shared_memory->handle(), chunk_size)); |
- data_size -= chunk_size; |
- data_ptr += chunk_size; |
- } |
-} |
- |
// ------ streams stuff ----- |
-void WebBlobRegistryImpl::registerStreamURL( |
- const WebURL& url, const WebString& content_type) { |
+void WebBlobRegistryImpl::registerStreamURL(const WebURL& url, |
+ const WebString& content_type) { |
DCHECK(ChildThreadImpl::current()); |
sender_->Send(new StreamHostMsg_StartBuilding(url, content_type.utf8())); |
} |
-void WebBlobRegistryImpl::registerStreamURL( |
- const WebURL& url, const WebURL& src_url) { |
+void WebBlobRegistryImpl::registerStreamURL(const WebURL& url, |
+ const WebURL& src_url) { |
DCHECK(ChildThreadImpl::current()); |
sender_->Send(new StreamHostMsg_Clone(url, src_url)); |
} |
void WebBlobRegistryImpl::addDataToStream(const WebURL& url, |
- const char* data, size_t length) { |
+ const char* data, |
+ size_t length) { |
DCHECK(ChildThreadImpl::current()); |
if (length == 0) |
return; |
if (length < kLargeThresholdBytes) { |
- storage::DataElement item; |
+ DataElement item; |
item.SetToBytes(data, length); |
sender_->Send(new StreamHostMsg_AppendBlobDataItem(url, item)); |
} else { |
// We handle larger amounts of data via SharedMemory instead of |
// writing it directly to the IPC channel. |
- size_t shared_memory_size = std::min( |
- length, kMaxSharedMemoryBytes); |
+ size_t shared_memory_size = std::min(length, kMaxSharedMemoryBytes); |
scoped_ptr<base::SharedMemory> shared_memory( |
ChildThreadImpl::AllocateSharedMemory(shared_memory_size, |
sender_.get())); |
@@ -256,4 +181,129 @@ void WebBlobRegistryImpl::unregisterStreamURL(const WebURL& url) { |
sender_->Send(new StreamHostMsg_Remove(url)); |
} |
+WebBlobRegistryImpl::BuilderImpl::BuilderImpl( |
+ const blink::WebString& uuid, |
+ const blink::WebString& content_type, |
+ ThreadSafeSender* sender) |
+ : uuid_(uuid.utf8()), content_type_(content_type.utf8()), sender_(sender) { |
+} |
+ |
+WebBlobRegistryImpl::BuilderImpl::~BuilderImpl() { |
+} |
+ |
+void WebBlobRegistryImpl::BuilderImpl::appendData( |
+ const WebThreadSafeData& data) { |
+ consolidation_.AddDataItem(data); |
+} |
+ |
+void WebBlobRegistryImpl::BuilderImpl::appendBlob(const WebString& uuid, |
+ uint64_t offset, |
+ uint64_t length) { |
+ consolidation_.AddBlobItem(uuid.utf8(), offset, length); |
+} |
+ |
+void WebBlobRegistryImpl::BuilderImpl::appendFile( |
+ const WebString& path, |
+ uint64_t offset, |
+ uint64_t length, |
+ double expected_modification_time) { |
+ consolidation_.AddFileItem( |
+ base::FilePath::FromUTF16Unsafe(base::string16(path)), offset, length, |
+ expected_modification_time); |
+} |
+ |
+void WebBlobRegistryImpl::BuilderImpl::appendFileSystemURL( |
+ const WebURL& fileSystemURL, |
+ uint64_t offset, |
+ uint64_t length, |
+ double expected_modification_time) { |
+ DCHECK(GURL(fileSystemURL).SchemeIsFileSystem()); |
+ consolidation_.AddFileSystemItem(GURL(fileSystemURL), offset, length, |
+ expected_modification_time); |
+} |
+ |
+void WebBlobRegistryImpl::BuilderImpl::build() { |
+ sender_->Send(new BlobHostMsg_StartBuilding(uuid_)); |
+ const auto& items = consolidation_.consolidated_items(); |
+ |
+ // We still need a buffer to hold the continuous block of data so the |
+ // DataElement can hold it. |
+ size_t buffer_size = 0; |
+ scoped_ptr<char[]> buffer; |
+ for (size_t i = 0; i < items.size(); i++) { |
+ const BlobConsolidation::ConsolidatedItem& item = items[i]; |
+ DataElement element; |
+ // NOTE: length == -1 when we want to use the whole file. This |
+ // only happens when we are creating a file object in Blink, and the file |
+ // object is the only item in the 'blob'. If we use that file blob to |
+ // create another blob, it is sent here as a 'file' item and not a blob, |
+ // and the correct size is populated. |
+ // static_cast<uint64>(-1) == kuint64max, which is what DataElement uses |
+ // to specificy "use the whole file". |
+ switch (item.type) { |
+ case DataElement::TYPE_BYTES: |
+ if (item.length > kLargeThresholdBytes) { |
+ SendOversizedDataForBlob(i); |
+ break; |
+ } |
+ if (buffer_size < item.length) { |
+ buffer.reset(new char[item.length]); |
+ buffer_size = item.length; |
+ } |
+ consolidation_.ReadMemory(i, 0, item.length, buffer.get()); |
+ element.SetToSharedBytes(buffer.get(), item.length); |
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_, element)); |
+ break; |
+ case DataElement::TYPE_FILE: |
+ element.SetToFilePathRange( |
+ item.path, item.offset, item.length, |
+ base::Time::FromDoubleT(item.expected_modification_time)); |
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_, element)); |
+ break; |
+ case DataElement::TYPE_BLOB: |
+ element.SetToBlobRange(item.blob_uuid, item.offset, item.length); |
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_, element)); |
+ break; |
+ case DataElement::TYPE_FILE_FILESYSTEM: |
+ element.SetToFileSystemUrlRange( |
+ item.filesystem_url, item.offset, item.length, |
+ base::Time::FromDoubleT(item.expected_modification_time)); |
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_, element)); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ } |
+ sender_->Send(new BlobHostMsg_FinishBuilding(uuid_, content_type_)); |
+} |
+ |
+void WebBlobRegistryImpl::BuilderImpl::SendOversizedDataForBlob( |
+ size_t consolidated_item_index) { |
+ TRACE_EVENT0("Blob", "Registry::SendOversizedBlobData"); |
+ const BlobConsolidation::ConsolidatedItem& item = |
+ consolidation_.consolidated_items()[consolidated_item_index]; |
+ // We handle larger amounts of data via SharedMemory instead of |
+ // writing it directly to the IPC channel. |
+ |
+ size_t data_size = item.length; |
+ size_t shared_memory_size = std::min(data_size, kMaxSharedMemoryBytes); |
+ scoped_ptr<base::SharedMemory> shared_memory( |
+ ChildThreadImpl::AllocateSharedMemory(shared_memory_size, sender_.get())); |
+ CHECK(shared_memory.get()); |
+ const bool mapped = shared_memory->Map(shared_memory_size); |
+ CHECK(mapped) << "Unable to map shared memory."; |
+ |
+ size_t offset = 0; |
+ while (data_size) { |
+ TRACE_EVENT0("Blob", "Registry::SendOversizedBlobItem"); |
+ size_t chunk_size = std::min(data_size, shared_memory_size); |
+ consolidation_.ReadMemory(consolidated_item_index, offset, chunk_size, |
+ shared_memory->memory()); |
+ sender_->Send(new BlobHostMsg_SyncAppendSharedMemory( |
+ uuid_, shared_memory->handle(), chunk_size)); |
+ data_size -= chunk_size; |
+ offset += chunk_size; |
+ } |
+} |
+ |
} // namespace content |