| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/blob_storage/blob_dispatcher_host.h" | 5 #include "content/browser/blob_storage/blob_dispatcher_host.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "content/browser/bad_message.h" | 10 #include "content/browser/bad_message.h" |
| 11 #include "content/browser/fileapi/chrome_blob_storage_context.h" | 11 #include "content/browser/fileapi/chrome_blob_storage_context.h" |
| 12 #include "content/common/fileapi/webblob_messages.h" | 12 #include "content/common/fileapi/webblob_messages.h" |
| 13 #include "ipc/ipc_platform_file.h" | 13 #include "ipc/ipc_platform_file.h" |
| 14 #include "storage/browser/blob/blob_storage_context.h" | 14 #include "storage/browser/blob/blob_storage_context.h" |
| 15 #include "storage/browser/blob/blob_transport_result.h" | 15 #include "storage/browser/blob/blob_transport_result.h" |
| 16 #include "storage/common/blob_storage/blob_item_bytes_request.h" | 16 #include "storage/common/blob_storage/blob_item_bytes_request.h" |
| 17 #include "storage/common/blob_storage/blob_item_bytes_response.h" | 17 #include "storage/common/blob_storage/blob_item_bytes_response.h" |
| 18 #include "storage/common/data_element.h" | 18 #include "storage/common/data_element.h" |
| 19 #include "url/gurl.h" | 19 #include "url/gurl.h" |
| 20 | 20 |
| 21 using storage::BlobStorageContext; | 21 using storage::BlobStorageContext; |
| 22 using storage::BlobStorageRegistry; | 22 using storage::BlobStorageRegistry; |
| 23 using storage::BlobTransportResult; | 23 using storage::BlobTransportResult; |
| 24 using storage::IPCBlobCreationCancelCode; | 24 using storage::IPCBlobCreationCancelCode; |
| 25 | 25 |
| 26 namespace content { | 26 namespace content { |
| 27 | 27 |
| 28 BlobDispatcherHost::BlobDispatcherHost( | 28 BlobDispatcherHost::BlobDispatcherHost( |
| 29 ChromeBlobStorageContext* blob_storage_context) | 29 ChromeBlobStorageContext* blob_storage_context, |
| 30 SetSuddenTerminationAllowedCallback set_sudden_termination_allowed) |
| 30 : BrowserMessageFilter(BlobMsgStart), | 31 : BrowserMessageFilter(BlobMsgStart), |
| 32 set_sudden_termination_allowed_(set_sudden_termination_allowed), |
| 31 blob_storage_context_(blob_storage_context) {} | 33 blob_storage_context_(blob_storage_context) {} |
| 32 | 34 |
| 33 BlobDispatcherHost::~BlobDispatcherHost() { | 35 BlobDispatcherHost::~BlobDispatcherHost() { |
| 34 ClearHostFromBlobStorageContext(); | 36 ClearHostFromBlobStorageContext(); |
| 35 } | 37 } |
| 36 | 38 |
| 37 void BlobDispatcherHost::OnChannelClosing() { | 39 void BlobDispatcherHost::OnChannelClosing() { |
| 38 ClearHostFromBlobStorageContext(); | 40 ClearHostFromBlobStorageContext(); |
| 39 public_blob_urls_.clear(); | 41 public_blob_urls_.clear(); |
| 40 blobs_inuse_map_.clear(); | 42 blobs_inuse_map_.clear(); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 68 return; | 70 return; |
| 69 } | 71 } |
| 70 blobs_inuse_map_[uuid] = 1; | 72 blobs_inuse_map_[uuid] = 1; |
| 71 BlobTransportResult result = async_builder_.RegisterBlobUUID( | 73 BlobTransportResult result = async_builder_.RegisterBlobUUID( |
| 72 uuid, content_type, content_disposition, referenced_blob_uuids, context); | 74 uuid, content_type, content_disposition, referenced_blob_uuids, context); |
| 73 switch (result) { | 75 switch (result) { |
| 74 case BlobTransportResult::BAD_IPC: | 76 case BlobTransportResult::BAD_IPC: |
| 75 blobs_inuse_map_.erase(uuid); | 77 blobs_inuse_map_.erase(uuid); |
| 76 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_OPERATION); | 78 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_OPERATION); |
| 77 break; | 79 break; |
| 78 ; | |
| 79 case BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN: | 80 case BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN: |
| 80 // The async builder builds the blob as broken, and we just need to send | 81 // The async builder builds the blob as broken, and we just need to send |
| 81 // the cancel message back to the renderer. | 82 // the cancel message back to the renderer. |
| 82 Send(new BlobStorageMsg_CancelBuildingBlob( | 83 Send(new BlobStorageMsg_CancelBuildingBlob( |
| 83 uuid, IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN)); | 84 uuid, IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN)); |
| 84 break; | 85 break; |
| 85 case BlobTransportResult::DONE: | 86 case BlobTransportResult::DONE: |
| 87 // This means the builder used to be empty, and we're successfully |
| 88 // building |
| 89 // the blob. |
| 90 if (async_builder_.blob_building_count() == 1) { |
| 91 set_sudden_termination_allowed_.Run(false); |
| 92 } |
| 86 break; | 93 break; |
| 87 case BlobTransportResult::CANCEL_MEMORY_FULL: | 94 case BlobTransportResult::CANCEL_MEMORY_FULL: |
| 88 case BlobTransportResult::CANCEL_FILE_ERROR: | 95 case BlobTransportResult::CANCEL_FILE_ERROR: |
| 89 case BlobTransportResult::CANCEL_UNKNOWN: | 96 case BlobTransportResult::CANCEL_UNKNOWN: |
| 90 case BlobTransportResult::PENDING_RESPONSES: | 97 case BlobTransportResult::PENDING_RESPONSES: |
| 91 NOTREACHED(); | 98 NOTREACHED(); |
| 92 break; | 99 break; |
| 93 } | 100 } |
| 94 } | 101 } |
| 95 | 102 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 110 // we decided to break a blob after RegisterBlobUUID is called. | 117 // we decided to break a blob after RegisterBlobUUID is called. |
| 111 // Second, if the last dereference of the blob happened on a different host, | 118 // Second, if the last dereference of the blob happened on a different host, |
| 112 // then we still haven't gotten rid of the 'building' state in the original | 119 // then we still haven't gotten rid of the 'building' state in the original |
| 113 // host. So we call cancel, and send the message just in case that happens. | 120 // host. So we call cancel, and send the message just in case that happens. |
| 114 if (async_builder_.IsBeingBuilt(uuid)) { | 121 if (async_builder_.IsBeingBuilt(uuid)) { |
| 115 async_builder_.CancelBuildingBlob( | 122 async_builder_.CancelBuildingBlob( |
| 116 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, | 123 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, |
| 117 context); | 124 context); |
| 118 Send(new BlobStorageMsg_CancelBuildingBlob( | 125 Send(new BlobStorageMsg_CancelBuildingBlob( |
| 119 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); | 126 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); |
| 127 AllowSuddenTerminationIfBuilderEmpty(); |
| 120 } | 128 } |
| 121 return; | 129 return; |
| 122 } | 130 } |
| 123 if (!async_builder_.IsBeingBuilt(uuid)) { | 131 if (!async_builder_.IsBeingBuilt(uuid)) { |
| 124 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); | 132 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
| 125 return; | 133 return; |
| 126 } | 134 } |
| 127 // |this| owns async_builder_ so using base::Unretained(this) is safe. | 135 // |this| owns async_builder_ so using base::Unretained(this) is safe. |
| 128 BlobTransportResult result = async_builder_.StartBuildingBlob( | 136 BlobTransportResult result = async_builder_.StartBuildingBlob( |
| 129 uuid, descriptions, context->memory_available(), context, | 137 uuid, descriptions, context->memory_available(), context, |
| 130 base::Bind(&BlobDispatcherHost::SendMemoryRequest, base::Unretained(this), | 138 base::Bind(&BlobDispatcherHost::SendMemoryRequest, base::Unretained(this), |
| 131 uuid)); | 139 uuid)); |
| 132 SendIPCResponse(uuid, result); | 140 SendIPCResponse(uuid, result); |
| 141 if (result != BlobTransportResult::PENDING_RESPONSES) { |
| 142 AllowSuddenTerminationIfBuilderEmpty(); |
| 143 } |
| 133 } | 144 } |
| 134 | 145 |
| 135 void BlobDispatcherHost::OnMemoryItemResponse( | 146 void BlobDispatcherHost::OnMemoryItemResponse( |
| 136 const std::string& uuid, | 147 const std::string& uuid, |
| 137 const std::vector<storage::BlobItemBytesResponse>& responses) { | 148 const std::vector<storage::BlobItemBytesResponse>& responses) { |
| 138 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 149 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 139 if (uuid.empty()) { | 150 if (uuid.empty()) { |
| 140 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); | 151 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
| 141 return; | 152 return; |
| 142 } | 153 } |
| 143 BlobStorageContext* context = this->context(); | 154 BlobStorageContext* context = this->context(); |
| 144 const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); | 155 const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); |
| 145 if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { | 156 if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { |
| 146 // We ignore messages for blobs that don't exist to handle the case where | 157 // We ignore messages for blobs that don't exist to handle the case where |
| 147 // the renderer de-refs a blob that we're still constructing, and there are | 158 // the renderer de-refs a blob that we're still constructing, and there are |
| 148 // no references to that blob. We ignore broken as well, in the case where | 159 // no references to that blob. We ignore broken as well, in the case where |
| 149 // we decided to break a blob after sending the memory request. | 160 // we decided to break a blob after sending the memory request. |
| 150 // Note: if a blob is broken, then it can't be in the async_builder. | |
| 151 // Second, if the last dereference of the blob happened on a different host, | 161 // Second, if the last dereference of the blob happened on a different host, |
| 152 // then we still haven't gotten rid of the 'building' state in the original | 162 // then we still haven't gotten rid of the 'building' state in the original |
| 153 // host. So we call cancel, and send the message just in case that happens. | 163 // host. So we call cancel, and send the message just in case that happens. |
| 154 if (async_builder_.IsBeingBuilt(uuid)) { | 164 if (async_builder_.IsBeingBuilt(uuid)) { |
| 155 async_builder_.CancelBuildingBlob( | 165 async_builder_.CancelBuildingBlob( |
| 156 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, | 166 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, |
| 157 context); | 167 context); |
| 158 Send(new BlobStorageMsg_CancelBuildingBlob( | 168 Send(new BlobStorageMsg_CancelBuildingBlob( |
| 159 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); | 169 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); |
| 170 AllowSuddenTerminationIfBuilderEmpty(); |
| 160 } | 171 } |
| 161 return; | 172 return; |
| 162 } | 173 } |
| 163 if (!async_builder_.IsBeingBuilt(uuid)) { | 174 if (!async_builder_.IsBeingBuilt(uuid)) { |
| 164 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); | 175 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
| 165 return; | 176 return; |
| 166 } | 177 } |
| 167 BlobTransportResult result = | 178 BlobTransportResult result = |
| 168 async_builder_.OnMemoryResponses(uuid, responses, context); | 179 async_builder_.OnMemoryResponses(uuid, responses, context); |
| 169 SendIPCResponse(uuid, result); | 180 SendIPCResponse(uuid, result); |
| 181 if (result != BlobTransportResult::PENDING_RESPONSES) { |
| 182 AllowSuddenTerminationIfBuilderEmpty(); |
| 183 } |
| 170 } | 184 } |
| 171 | 185 |
| 172 void BlobDispatcherHost::OnCancelBuildingBlob( | 186 void BlobDispatcherHost::OnCancelBuildingBlob( |
| 173 const std::string& uuid, | 187 const std::string& uuid, |
| 174 const storage::IPCBlobCreationCancelCode code) { | 188 const storage::IPCBlobCreationCancelCode code) { |
| 175 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 189 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 176 if (uuid.empty()) { | 190 if (uuid.empty()) { |
| 177 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); | 191 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
| 178 return; | 192 return; |
| 179 } | 193 } |
| 180 BlobStorageContext* context = this->context(); | 194 BlobStorageContext* context = this->context(); |
| 181 const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); | 195 const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); |
| 182 if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { | 196 if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { |
| 183 // We ignore messages for blobs that don't exist to handle the case where | 197 // We ignore messages for blobs that don't exist to handle the case where |
| 184 // the renderer de-refs a blob that we're still constructing, and there are | 198 // the renderer de-refs a blob that we're still constructing, and there are |
| 185 // no references to that blob. We ignore broken as well, in the case where | 199 // no references to that blob. We ignore broken as well, in the case where |
| 186 // we decided to break a blob and the renderer also decided to cancel. | 200 // we decided to break a blob and the renderer also decided to cancel. |
| 187 // Note: if a blob is broken, then it can't be in the async_builder. | |
| 188 // Second, if the last dereference of the blob happened on a different host, | 201 // Second, if the last dereference of the blob happened on a different host, |
| 189 // then we still haven't gotten rid of the 'building' state in the original | 202 // then we still haven't gotten rid of the 'building' state in the original |
| 190 // host. So we call cancel just in case this happens. | 203 // host. So we call cancel just in case this happens. |
| 191 async_builder_.CancelBuildingBlob( | 204 if (async_builder_.IsBeingBuilt(uuid)) { |
| 192 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, | 205 async_builder_.CancelBuildingBlob( |
| 193 context); | 206 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, |
| 207 context); |
| 208 AllowSuddenTerminationIfBuilderEmpty(); |
| 209 } |
| 194 return; | 210 return; |
| 195 } | 211 } |
| 196 if (!async_builder_.IsBeingBuilt(uuid)) { | 212 if (!async_builder_.IsBeingBuilt(uuid)) { |
| 197 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); | 213 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); |
| 198 return; | 214 return; |
| 199 } | 215 } |
| 200 VLOG(1) << "Blob construction of " << uuid << " cancelled by renderer. " | 216 VLOG(1) << "Blob construction of " << uuid << " cancelled by renderer. " |
| 201 << " Reason: " << static_cast<int>(code) << "."; | 217 << " Reason: " << static_cast<int>(code) << "."; |
| 202 async_builder_.CancelBuildingBlob(uuid, code, context); | 218 async_builder_.CancelBuildingBlob(uuid, code, context); |
| 219 AllowSuddenTerminationIfBuilderEmpty(); |
| 203 } | 220 } |
| 204 | 221 |
| 205 void BlobDispatcherHost::OnIncrementBlobRefCount(const std::string& uuid) { | 222 void BlobDispatcherHost::OnIncrementBlobRefCount(const std::string& uuid) { |
| 206 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 223 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 207 BlobStorageContext* context = this->context(); | 224 BlobStorageContext* context = this->context(); |
| 208 if (uuid.empty() || !context->registry().HasEntry(uuid)) { | 225 if (uuid.empty() || !context->registry().HasEntry(uuid)) { |
| 209 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_OPERATION); | 226 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_OPERATION); |
| 210 return; | 227 return; |
| 211 } | 228 } |
| 212 context->IncrementBlobRefCount(uuid); | 229 context->IncrementBlobRefCount(uuid); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 227 // If the blob has been deleted in the context and we're still building it, | 244 // If the blob has been deleted in the context and we're still building it, |
| 228 // this means we have no references waiting to read it. Clear the building | 245 // this means we have no references waiting to read it. Clear the building |
| 229 // state and send a cancel message to the renderer. | 246 // state and send a cancel message to the renderer. |
| 230 if (async_builder_.IsBeingBuilt(uuid) && | 247 if (async_builder_.IsBeingBuilt(uuid) && |
| 231 !context->registry().HasEntry(uuid)) { | 248 !context->registry().HasEntry(uuid)) { |
| 232 async_builder_.CancelBuildingBlob( | 249 async_builder_.CancelBuildingBlob( |
| 233 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, | 250 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, |
| 234 context); | 251 context); |
| 235 Send(new BlobStorageMsg_CancelBuildingBlob( | 252 Send(new BlobStorageMsg_CancelBuildingBlob( |
| 236 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); | 253 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING)); |
| 254 AllowSuddenTerminationIfBuilderEmpty(); |
| 237 } | 255 } |
| 238 } | 256 } |
| 239 } | 257 } |
| 240 | 258 |
| 241 void BlobDispatcherHost::OnRegisterPublicBlobURL(const GURL& public_url, | 259 void BlobDispatcherHost::OnRegisterPublicBlobURL(const GURL& public_url, |
| 242 const std::string& uuid) { | 260 const std::string& uuid) { |
| 243 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 261 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 244 BlobStorageContext* context = this->context(); | 262 BlobStorageContext* context = this->context(); |
| 245 if (uuid.empty() || !IsInUseInHost(uuid) || | 263 if (uuid.empty() || !IsInUseInHost(uuid) || |
| 246 context->registry().IsURLMapped(public_url)) { | 264 context->registry().IsURLMapped(public_url)) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 | 338 |
| 321 void BlobDispatcherHost::ClearHostFromBlobStorageContext() { | 339 void BlobDispatcherHost::ClearHostFromBlobStorageContext() { |
| 322 BlobStorageContext* context = this->context(); | 340 BlobStorageContext* context = this->context(); |
| 323 for (const auto& url : public_blob_urls_) { | 341 for (const auto& url : public_blob_urls_) { |
| 324 context->RevokePublicBlobURL(url); | 342 context->RevokePublicBlobURL(url); |
| 325 } | 343 } |
| 326 for (const auto& uuid_refnum_pair : blobs_inuse_map_) { | 344 for (const auto& uuid_refnum_pair : blobs_inuse_map_) { |
| 327 for (int i = 0; i < uuid_refnum_pair.second; ++i) | 345 for (int i = 0; i < uuid_refnum_pair.second; ++i) |
| 328 context->DecrementBlobRefCount(uuid_refnum_pair.first); | 346 context->DecrementBlobRefCount(uuid_refnum_pair.first); |
| 329 } | 347 } |
| 330 async_builder_.CancelAll(context); | 348 if (!async_builder_.IsEmpty()) { |
| 349 async_builder_.CancelAll(context); |
| 350 set_sudden_termination_allowed_.Run(true); |
| 351 } |
| 352 } |
| 353 |
| 354 void BlobDispatcherHost::AllowSuddenTerminationIfBuilderEmpty() { |
| 355 if (async_builder_.IsEmpty()) { |
| 356 set_sudden_termination_allowed_.Run(true); |
| 357 } |
| 331 } | 358 } |
| 332 | 359 |
| 333 } // namespace content | 360 } // namespace content |
| OLD | NEW |