Chromium Code Reviews| 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..456bc872e75105637510bf87114278270a5c8bc8 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,9 +26,8 @@ |
| using storage::BlobStorageContext; |
| using storage::BlobStorageRegistry; |
| -using storage::BlobTransportResult; |
| +using storage::BlobStatus; |
| using storage::DataElement; |
| -using storage::IPCBlobCreationCancelCode; |
| using storage::FileSystemURL; |
| namespace content { |
| @@ -63,11 +63,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 +77,21 @@ 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)); |
| + blobs_inuse_map_[uuid] = 1; |
| ChildProcessSecurityPolicyImpl* security_policy = |
| ChildProcessSecurityPolicyImpl::GetInstance(); |
| @@ -159,20 +105,22 @@ 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)); |
| + std::unique_ptr<storage::BlobDataHandle> broken_handle = |
| + context->AddBrokenBlob(uuid, content_type, content_disposition, |
| + BlobStatus::ERR_FILE_WRITE_FAILED); |
| + context->IncrementBlobRefCount(uuid); |
|
kinuko
2016/11/10 05:16:36
Could you help me understand, I might be lost-- we
dmurph
2016/11/10 19:53:19
Yes, the context now gives the one and only handle
|
| + 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)); |
| + std::unique_ptr<storage::BlobDataHandle> broken_handle = |
| + context->AddBrokenBlob(uuid, content_type, content_disposition, |
| + BlobStatus::ERR_FILE_WRITE_FAILED); |
| + context->IncrementBlobRefCount(uuid); |
| + SendFinalBlobStatus(uuid, BlobStatus::ERR_FILE_WRITE_FAILED); |
| return; |
| } |
| break; |
| @@ -193,12 +141,12 @@ 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, |
| + 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)); |
| } |
| void BlobDispatcherHost::OnMemoryItemResponse( |
| @@ -206,12 +154,12 @@ 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 |
| @@ -220,35 +168,35 @@ void BlobDispatcherHost::OnMemoryItemResponse( |
| // 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); |
| + SendFinalBlobStatus(uuid, |
| + BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING); |
| } |
| 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); |
| + BlobStatus result = |
| + transport_host_.OnMemoryResponses(uuid, responses, context); |
| + if (BlobStatusIsPending(result)) |
| + return; |
| + SendFinalBlobStatus(uuid, result); |
|
kinuko
2016/11/10 05:16:36
OnMemoryResponses could return INVALID_CONSTRUCTIO
dmurph
2016/11/10 19:53:19
So we remove the blob before returning a bad IPC s
kinuko
2016/11/11 17:51:14
Sorry, I'm not following. What change corresponds
|
| } |
| -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 |
| @@ -257,20 +205,20 @@ void BlobDispatcherHost::OnCancelBuildingBlob( |
| // 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) { |
| @@ -310,13 +258,12 @@ void BlobDispatcherHost::OnDecrementBlobRefCount(const std::string& 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) && |
| + 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); |
| + SendFinalBlobStatus(uuid, |
| + BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING); |
| } |
| } |
| } |
| @@ -372,47 +319,27 @@ 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) { |
| + if (storage::BlobStatusIsBadIPC(status)) { |
| + blobs_inuse_map_.erase(uuid); |
| + bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED); |
| + return; |
| } |
| - NOTREACHED(); |
| + DCHECK(!BlobStatusIsPending(status)); |
| + Send(new BlobStorageMsg_SendBlobStatus(uuid, status)); |
| } |
| bool BlobDispatcherHost::IsInUseInHost(const std::string& uuid) { |
| @@ -432,7 +359,7 @@ void BlobDispatcherHost::ClearHostFromBlobStorageContext() { |
| for (int i = 0; i < uuid_refnum_pair.second; ++i) |
| context->DecrementBlobRefCount(uuid_refnum_pair.first); |
| } |
| - async_builder_.CancelAll(context); |
| + transport_host_.CancelAll(context); |
| } |
| } // namespace content |