| 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
|
|
|