Index: content/browser/blob_storage/blob_dispatcher_host.cc |
diff --git a/content/browser/blob_storage/blob_dispatcher_host.cc b/content/browser/blob_storage/blob_dispatcher_host.cc |
index 2269cc645efa1d56ac2b50ef544149f84c9de160..bea813ddc5c4f7abdfc20eccc633918fb790b792 100644 |
--- a/content/browser/blob_storage/blob_dispatcher_host.cc |
+++ b/content/browser/blob_storage/blob_dispatcher_host.cc |
@@ -14,8 +14,9 @@ |
#include "content/browser/fileapi/browser_file_system_helper.h" |
#include "content/common/fileapi/webblob_messages.h" |
#include "ipc/ipc_platform_file.h" |
+#include "storage/browser/blob/blob_data_handle.h" |
+#include "storage/browser/blob/blob_entry.h" |
#include "storage/browser/blob/blob_storage_context.h" |
-#include "storage/browser/blob/blob_transport_result.h" |
#include "storage/browser/fileapi/file_system_context.h" |
#include "storage/browser/fileapi/file_system_url.h" |
#include "storage/common/blob_storage/blob_item_bytes_request.h" |
@@ -25,13 +26,17 @@ |
using storage::BlobStorageContext; |
using storage::BlobStorageRegistry; |
-using storage::BlobTransportResult; |
+using storage::BlobStatus; |
using storage::DataElement; |
-using storage::IPCBlobCreationCancelCode; |
using storage::FileSystemURL; |
namespace content { |
namespace { |
+using storage::BlobStorageContext; |
+using storage::BlobStorageRegistry; |
+using storage::BlobStatus; |
+using storage::DataElement; |
+using storage::FileSystemURL; |
// These are used for UMA stats, don't change. |
enum RefcountOperation { |
@@ -42,6 +47,16 @@ enum RefcountOperation { |
} // namespace |
+BlobDispatcherHost::HostedBlobState::HostedBlobState( |
+ std::unique_ptr<storage::BlobDataHandle> handle) |
+ : handle(std::move(handle)) {} |
+BlobDispatcherHost::HostedBlobState::~HostedBlobState() {} |
+ |
+BlobDispatcherHost::HostedBlobState::HostedBlobState(HostedBlobState&&) = |
+ default; |
+BlobDispatcherHost::HostedBlobState& BlobDispatcherHost::HostedBlobState:: |
+operator=(BlobDispatcherHost::HostedBlobState&&) = default; |
+ |
BlobDispatcherHost::BlobDispatcherHost( |
int process_id, |
scoped_refptr<ChromeBlobStorageContext> blob_storage_context, |
@@ -63,11 +78,11 @@ void BlobDispatcherHost::OnChannelClosing() { |
bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message) { |
bool handled = true; |
+ // Note: The only time a renderer sends a blob status message is to cancel. |
IPC_BEGIN_MESSAGE_MAP(BlobDispatcherHost, message) |
- IPC_MESSAGE_HANDLER(BlobStorageMsg_RegisterBlobUUID, OnRegisterBlobUUID) |
- IPC_MESSAGE_HANDLER(BlobStorageMsg_StartBuildingBlob, OnStartBuildingBlob) |
+ IPC_MESSAGE_HANDLER(BlobStorageMsg_RegisterBlob, OnRegisterBlob) |
IPC_MESSAGE_HANDLER(BlobStorageMsg_MemoryItemResponse, OnMemoryItemResponse) |
- IPC_MESSAGE_HANDLER(BlobStorageMsg_CancelBuildingBlob, OnCancelBuildingBlob) |
+ IPC_MESSAGE_HANDLER(BlobStorageMsg_SendBlobStatus, OnCancelBuildingBlob) |
IPC_MESSAGE_HANDLER(BlobHostMsg_IncrementRefCount, OnIncrementBlobRefCount) |
IPC_MESSAGE_HANDLER(BlobHostMsg_DecrementRefCount, OnDecrementBlobRefCount) |
IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL, OnRegisterPublicBlobURL) |
@@ -77,75 +92,20 @@ bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message) { |
return handled; |
} |
-void BlobDispatcherHost::OnRegisterBlobUUID( |
+void BlobDispatcherHost::OnRegisterBlob( |
const std::string& uuid, |
const std::string& content_type, |
const std::string& content_disposition, |
- const std::set<std::string>& referenced_blob_uuids) { |
+ const std::vector<storage::DataElement>& descriptions) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
BlobStorageContext* context = this->context(); |
if (uuid.empty() || context->registry().HasEntry(uuid) || |
- async_builder_.IsBeingBuilt(uuid)) { |
+ transport_host_.IsBeingBuilt(uuid)) { |
bad_message::ReceivedBadMessage(this, bad_message::BDH_UUID_REGISTERED); |
return; |
} |
- blobs_inuse_map_[uuid] = 1; |
- BlobTransportResult result = async_builder_.RegisterBlobUUID( |
- uuid, content_type, content_disposition, referenced_blob_uuids, context); |
- switch (result) { |
- case BlobTransportResult::BAD_IPC: |
- blobs_inuse_map_.erase(uuid); |
- bad_message::ReceivedBadMessage(this, |
- bad_message::BDH_CONSTRUCTION_FAILED); |
- break; |
- case BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN: |
- // The async builder builds the blob as broken, and we just need to send |
- // the cancel message back to the renderer. |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN)); |
- break; |
- case BlobTransportResult::DONE: |
- break; |
- case BlobTransportResult::CANCEL_MEMORY_FULL: |
- case BlobTransportResult::CANCEL_FILE_ERROR: |
- case BlobTransportResult::CANCEL_UNKNOWN: |
- case BlobTransportResult::PENDING_RESPONSES: |
- NOTREACHED(); |
- break; |
- } |
-} |
-void BlobDispatcherHost::OnStartBuildingBlob( |
- const std::string& uuid, |
- const std::vector<storage::DataElement>& descriptions) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- if (uuid.empty()) { |
- SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
- return; |
- } |
- BlobStorageContext* context = this->context(); |
- const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); |
- if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { |
- // We ignore messages for blobs that don't exist to handle the case where |
- // the renderer de-refs a blob that we're still constructing, and there are |
- // no references to that blob. We ignore broken as well, in the case where |
- // we decided to break a blob after RegisterBlobUUID is called. |
- // Second, if the last dereference of the blob happened on a different host, |
- // then we still haven't gotten rid of the 'building' state in the original |
- // host. So we call cancel, and send the message just in case that happens. |
- if (async_builder_.IsBeingBuilt(uuid)) { |
- async_builder_.CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, |
- context); |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); |
- } |
- return; |
- } |
- if (!async_builder_.IsBeingBuilt(uuid)) { |
- SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
- return; |
- } |
+ DCHECK(!base::ContainsKey(blobs_inuse_map_, uuid)); |
ChildProcessSecurityPolicyImpl* security_policy = |
ChildProcessSecurityPolicyImpl::GetInstance(); |
@@ -159,20 +119,24 @@ void BlobDispatcherHost::OnStartBuildingBlob( |
if (!FileSystemURLIsValid(file_system_context_.get(), filesystem_url) || |
!security_policy->CanReadFileSystemFile(process_id_, |
filesystem_url)) { |
- async_builder_.CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED, context); |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED)); |
+ HostedBlobState hosted_state( |
+ context->AddBrokenBlob(uuid, content_type, content_disposition, |
+ BlobStatus::ERR_FILE_WRITE_FAILED)); |
+ blobs_inuse_map_.insert( |
+ std::make_pair(uuid, std::move(hosted_state))); |
+ SendFinalBlobStatus(uuid, BlobStatus::ERR_FILE_WRITE_FAILED); |
return; |
} |
break; |
} |
case storage::DataElement::TYPE_FILE: { |
if (!security_policy->CanReadFile(process_id_, item.path())) { |
- async_builder_.CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED, context); |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED)); |
+ HostedBlobState hosted_state( |
+ context->AddBrokenBlob(uuid, content_type, content_disposition, |
+ BlobStatus::ERR_FILE_WRITE_FAILED)); |
+ blobs_inuse_map_.insert( |
+ std::make_pair(uuid, std::move(hosted_state))); |
+ SendFinalBlobStatus(uuid, BlobStatus::ERR_FILE_WRITE_FAILED); |
return; |
} |
break; |
@@ -193,12 +157,13 @@ void BlobDispatcherHost::OnStartBuildingBlob( |
} |
} |
- // |this| owns async_builder_ so using base::Unretained(this) is safe. |
- BlobTransportResult result = async_builder_.StartBuildingBlob( |
- uuid, descriptions, context->memory_available(), context, |
+ HostedBlobState hosted_state(transport_host_.StartBuildingBlob( |
+ uuid, content_type, content_disposition, descriptions, context, |
base::Bind(&BlobDispatcherHost::SendMemoryRequest, base::Unretained(this), |
- uuid)); |
- SendIPCResponse(uuid, result); |
+ uuid), |
+ base::Bind(&BlobDispatcherHost::SendFinalBlobStatus, |
+ base::Unretained(this), uuid))); |
+ blobs_inuse_map_.insert(std::make_pair(uuid, std::move(hosted_state))); |
} |
void BlobDispatcherHost::OnMemoryItemResponse( |
@@ -206,71 +171,65 @@ void BlobDispatcherHost::OnMemoryItemResponse( |
const std::vector<storage::BlobItemBytesResponse>& responses) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
if (uuid.empty()) { |
- SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
+ bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED); |
return; |
} |
BlobStorageContext* context = this->context(); |
- const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); |
- if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { |
+ const storage::BlobEntry* entry = context->registry().GetEntry(uuid); |
+ if (!entry || BlobStatusIsError(entry->status())) { |
// We ignore messages for blobs that don't exist to handle the case where |
// the renderer de-refs a blob that we're still constructing, and there are |
// no references to that blob. We ignore broken as well, in the case where |
// we decided to break a blob after sending the memory request. |
- // Note: if a blob is broken, then it can't be in the async_builder. |
+ // Note: if a blob is broken, then it can't be in the transport_host. |
// Second, if the last dereference of the blob happened on a different host, |
// then we still haven't gotten rid of the 'building' state in the original |
// host. So we call cancel, and send the message just in case that happens. |
- if (async_builder_.IsBeingBuilt(uuid)) { |
- async_builder_.CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, |
- context); |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); |
+ if (transport_host_.IsBeingBuilt(uuid)) { |
+ transport_host_.CancelBuildingBlob( |
+ uuid, BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING, context); |
} |
return; |
} |
- if (!async_builder_.IsBeingBuilt(uuid)) { |
- SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
+ if (!transport_host_.IsBeingBuilt(uuid)) { |
+ bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED); |
return; |
} |
- BlobTransportResult result = |
- async_builder_.OnMemoryResponses(uuid, responses, context); |
- SendIPCResponse(uuid, result); |
+ transport_host_.OnMemoryResponses(uuid, responses, context); |
} |
-void BlobDispatcherHost::OnCancelBuildingBlob( |
- const std::string& uuid, |
- const storage::IPCBlobCreationCancelCode code) { |
+void BlobDispatcherHost::OnCancelBuildingBlob(const std::string& uuid, |
+ const storage::BlobStatus code) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
if (uuid.empty()) { |
- SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
+ bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED); |
return; |
} |
BlobStorageContext* context = this->context(); |
- const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); |
- if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { |
+ const storage::BlobEntry* entry = context->registry().GetEntry(uuid); |
+ if (!entry || BlobStatusIsError(entry->status())) { |
// We ignore messages for blobs that don't exist to handle the case where |
// the renderer de-refs a blob that we're still constructing, and there are |
// no references to that blob. We ignore broken as well, in the case where |
// we decided to break a blob and the renderer also decided to cancel. |
- // Note: if a blob is broken, then it can't be in the async_builder. |
+ // Note: if a blob is broken, then it can't be in the transport_host. |
// Second, if the last dereference of the blob happened on a different host, |
// then we still haven't gotten rid of the 'building' state in the original |
// host. So we call cancel just in case this happens. |
- if (async_builder_.IsBeingBuilt(uuid)) { |
- async_builder_.CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, |
- context); |
+ if (transport_host_.IsBeingBuilt(uuid)) { |
+ transport_host_.CancelBuildingBlob( |
+ uuid, BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING, context); |
} |
return; |
} |
- if (!async_builder_.IsBeingBuilt(uuid)) { |
- SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
+ if (!transport_host_.IsBeingBuilt(uuid) || |
+ !storage::BlobStatusIsError(code)) { |
+ bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED); |
return; |
} |
VLOG(1) << "Blob construction of " << uuid << " cancelled by renderer. " |
<< " Reason: " << static_cast<int>(code) << "."; |
- async_builder_.CancelBuildingBlob(uuid, code, context); |
+ transport_host_.CancelBuildingBlob(uuid, code, context); |
} |
void BlobDispatcherHost::OnIncrementBlobRefCount(const std::string& uuid) { |
@@ -286,8 +245,13 @@ void BlobDispatcherHost::OnIncrementBlobRefCount(const std::string& uuid) { |
BDH_TRACING_ENUM_LAST); |
return; |
} |
- context->IncrementBlobRefCount(uuid); |
- blobs_inuse_map_[uuid] += 1; |
+ auto state_it = blobs_inuse_map_.find(uuid); |
+ if (state_it != blobs_inuse_map_.end()) { |
+ state_it->second.refcount += 1; |
+ return; |
+ } |
+ blobs_inuse_map_.insert(std::make_pair( |
+ uuid, HostedBlobState(context->GetBlobDataFromUUID(uuid)))); |
} |
void BlobDispatcherHost::OnDecrementBlobRefCount(const std::string& uuid) { |
@@ -297,26 +261,23 @@ void BlobDispatcherHost::OnDecrementBlobRefCount(const std::string& uuid) { |
this, bad_message::BDH_INVALID_REFCOUNT_OPERATION); |
return; |
} |
- if (!IsInUseInHost(uuid)) { |
+ auto state_it = blobs_inuse_map_.find(uuid); |
+ if (state_it == blobs_inuse_map_.end()) { |
UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidReference", BDH_DECREMENT, |
BDH_TRACING_ENUM_LAST); |
return; |
} |
- BlobStorageContext* context = this->context(); |
- context->DecrementBlobRefCount(uuid); |
- blobs_inuse_map_[uuid] -= 1; |
- if (blobs_inuse_map_[uuid] == 0) { |
- blobs_inuse_map_.erase(uuid); |
- // If the blob has been deleted in the context and we're still building it, |
- // this means we have no references waiting to read it. Clear the building |
- // state and send a cancel message to the renderer. |
- if (async_builder_.IsBeingBuilt(uuid) && |
+ state_it->second.refcount -= 1; |
+ if (state_it->second.refcount == 0) { |
+ blobs_inuse_map_.erase(state_it); |
+ |
+ // If we're being built still and we don't have any other references, cancel |
+ // construction. |
+ BlobStorageContext* context = this->context(); |
+ if (transport_host_.IsBeingBuilt(uuid) && |
!context->registry().HasEntry(uuid)) { |
- async_builder_.CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, |
- context); |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); |
+ transport_host_.CancelBuildingBlob( |
+ uuid, BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING, context); |
} |
} |
} |
@@ -372,55 +333,33 @@ storage::BlobStorageContext* BlobDispatcherHost::context() { |
void BlobDispatcherHost::SendMemoryRequest( |
const std::string& uuid, |
- std::unique_ptr<std::vector<storage::BlobItemBytesRequest>> requests, |
- std::unique_ptr<std::vector<base::SharedMemoryHandle>> memory_handles, |
- std::unique_ptr<std::vector<base::File>> files) { |
+ std::vector<storage::BlobItemBytesRequest> requests, |
+ std::vector<base::SharedMemoryHandle> memory_handles, |
+ std::vector<base::File> files) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
std::vector<IPC::PlatformFileForTransit> file_handles; |
- // TODO(dmurph): Support file-backed blob transportation. |
- DCHECK(files->empty()); |
- Send(new BlobStorageMsg_RequestMemoryItem(uuid, *requests, *memory_handles, |
+ for (base::File& file : files) { |
+ file_handles.push_back(IPC::TakePlatformFileForTransit(std::move(file))); |
+ } |
+ Send(new BlobStorageMsg_RequestMemoryItem(uuid, requests, memory_handles, |
file_handles)); |
} |
-void BlobDispatcherHost::SendIPCResponse(const std::string& uuid, |
- storage::BlobTransportResult result) { |
- switch (result) { |
- case BlobTransportResult::BAD_IPC: |
- bad_message::ReceivedBadMessage(this, |
- bad_message::BDH_CONSTRUCTION_FAILED); |
- return; |
- case BlobTransportResult::CANCEL_MEMORY_FULL: |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY)); |
- return; |
- case BlobTransportResult::CANCEL_FILE_ERROR: |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED)); |
- return; |
- case BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN: |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN)); |
- return; |
- case BlobTransportResult::CANCEL_UNKNOWN: |
- Send(new BlobStorageMsg_CancelBuildingBlob( |
- uuid, IPCBlobCreationCancelCode::UNKNOWN)); |
- return; |
- case BlobTransportResult::PENDING_RESPONSES: |
- return; |
- case BlobTransportResult::DONE: |
- Send(new BlobStorageMsg_DoneBuildingBlob(uuid)); |
- return; |
+void BlobDispatcherHost::SendFinalBlobStatus(const std::string& uuid, |
+ BlobStatus status) { |
+ DCHECK(!BlobStatusIsPending(status)); |
+ if (storage::BlobStatusIsBadIPC(status)) { |
+ bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED); |
} |
- NOTREACHED(); |
+ Send(new BlobStorageMsg_SendBlobStatus(uuid, status)); |
} |
bool BlobDispatcherHost::IsInUseInHost(const std::string& uuid) { |
- return blobs_inuse_map_.find(uuid) != blobs_inuse_map_.end(); |
+ return base::ContainsKey(blobs_inuse_map_, uuid); |
} |
bool BlobDispatcherHost::IsUrlRegisteredInHost(const GURL& blob_url) { |
- return public_blob_urls_.find(blob_url) != public_blob_urls_.end(); |
+ return base::ContainsKey(public_blob_urls_, blob_url); |
} |
void BlobDispatcherHost::ClearHostFromBlobStorageContext() { |
@@ -428,11 +367,9 @@ void BlobDispatcherHost::ClearHostFromBlobStorageContext() { |
for (const auto& url : public_blob_urls_) { |
context->RevokePublicBlobURL(url); |
} |
- for (const auto& uuid_refnum_pair : blobs_inuse_map_) { |
- for (int i = 0; i < uuid_refnum_pair.second; ++i) |
- context->DecrementBlobRefCount(uuid_refnum_pair.first); |
- } |
- async_builder_.CancelAll(context); |
+ // Keep the blobs alive for the BlobTransportHost call. |
+ transport_host_.CancelAll(context); |
+ blobs_inuse_map_.clear(); |
} |
} // namespace content |