Chromium Code Reviews| Index: content/child/webblobregistry_impl.cc |
| diff --git a/content/child/webblobregistry_impl.cc b/content/child/webblobregistry_impl.cc |
| index 22f6f43acdc25c351b2e70b575a56bc04540d2a4..a162fbf6f5d3ff99c8f0e80aaf3b64cc0ee7c713 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 { |
| @@ -39,82 +42,53 @@ WebBlobRegistryImpl::WebBlobRegistryImpl(ThreadSafeSender* sender) |
| TRACE_EVENT0("Blob", "Init"); |
| } |
| -WebBlobRegistryImpl::~WebBlobRegistryImpl() { |
| +WebBlobRegistryImpl::~WebBlobRegistryImpl() {} |
| + |
| +blink::WebBlobRegistry::Builder* WebBlobRegistryImpl::createBuilder( |
| + const blink::WebString& uuid, const blink::WebString& contentType) { |
| + return new BuilderImpl(uuid, contentType, sender_.get()); |
| } |
| -void WebBlobRegistryImpl::registerBlobData( |
| - const blink::WebString& uuid, const blink::WebBlobData& data) { |
| +void WebBlobRegistryImpl::registerBlobData(const blink::WebString& uuid, |
| + const blink::WebBlobData& data) { |
| TRACE_EVENT0("Blob", "Registry::RegisterBlob"); |
| - const std::string uuid_str(uuid.utf8()); |
| - |
| - storage::DataElement data_buffer; |
| - data_buffer.SetToEmptyBytes(); |
| + 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) { |
|
michaeln
2015/06/17 03:17:55
This filter for blink giving us empty items got lo
dmurph
2015/06/17 18:29:51
Done. I added this check in the append methods in
|
| - 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 +99,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,94 +108,37 @@ 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) { |
| +void WebBlobRegistryImpl::addDataToStream(const WebURL& url, const char* data, |
| + size_t length) { |
| DCHECK(ChildThreadImpl::current()); |
| - if (length == 0) |
| - return; |
| + 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())); |
| CHECK(shared_memory.get()); |
| - if (!shared_memory->Map(shared_memory_size)) |
| - CHECK(false); |
| + if (!shared_memory->Map(shared_memory_size)) CHECK(false); |
| size_t remaining_bytes = length; |
| const char* current_ptr = data; |
| @@ -256,4 +173,138 @@ void WebBlobRegistryImpl::unregisterStreamURL(const WebURL& url) { |
| sender_->Send(new StreamHostMsg_Remove(url)); |
| } |
| +WebBlobRegistryImpl::BuilderImpl::BuilderImpl( |
| + const blink::WebString& uuid, const blink::WebString& contentType, |
| + ThreadSafeSender* sender) |
| + : uuid_(uuid.utf8()), content_type_(contentType.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, offset, length); |
| +} |
| + |
| +void WebBlobRegistryImpl::BuilderImpl::appendFile( |
| + const WebString& path, uint64_t offset, uint64_t length, |
| + double expectedModificationTime) { |
| + consolidation_.AddFileItem(path, offset, length, expectedModificationTime); |
| +} |
| + |
| +void WebBlobRegistryImpl::BuilderImpl::appendFileSystemURL( |
| + const WebURL& fileSystemURL, uint64_t offset, uint64_t length, |
| + double expectedModificationTime) { |
| + consolidation_.AddFileSystemItem(fileSystemURL, offset, length, |
| + expectedModificationTime); |
| + // 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". |
| + storage::DataElement item; |
| + DCHECK(GURL(fileSystemURL).SchemeIsFileSystem()); |
| + item.SetToFileSystemUrlRange( |
| + GURL(fileSystemURL), static_cast<uint64>(offset), |
| + static_cast<uint64>(length), |
| + base::Time::FromDoubleT(expectedModificationTime)); |
| + sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_, item)); |
|
michaeln
2015/06/17 03:17:55
This message being sent looks out of place as does
dmurph
2015/06/17 18:29:51
Whoops, you're right, thanks.
|
| +} |
| + |
| +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( |
| + base::FilePath::FromUTF16Unsafe(base::string16(item.path)), |
| + static_cast<uint64>(item.offset), static_cast<uint64>(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.utf8(), |
| + static_cast<uint64>(item.offset), |
| + static_cast<uint64>(item.length)); |
| + sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_, element)); |
| + break; |
| + case DataElement::TYPE_FILE_FILESYSTEM: |
| + DCHECK(GURL(item.filesystem_url).SchemeIsFileSystem()); |
| + element.SetToFileSystemUrlRange( |
| + GURL(item.filesystem_url), static_cast<uint64>(item.offset), |
| + static_cast<uint64>(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(item.length, 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 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, |
| + static_cast<char*>(shared_memory->memory())); |
| + sender_->Send(new BlobHostMsg_SyncAppendSharedMemory( |
| + uuid_, shared_memory->handle(), chunk_size)); |
| + data_size -= chunk_size; |
| + offset += chunk_size; |
| + } |
| +} |
| + |
| } // namespace content |