Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(664)

Side by Side Diff: content/browser/blob_storage/blob_dispatcher_host.cc

Issue 2448353002: [BlobAsync] Moving async handling into BlobStorageContext & quota out. (Closed)
Patch Set: Cleaned up more Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "base/metrics/histogram_macros.h" 10 #include "base/metrics/histogram_macros.h"
11 #include "content/browser/bad_message.h" 11 #include "content/browser/bad_message.h"
12 #include "content/browser/blob_storage/chrome_blob_storage_context.h" 12 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
13 #include "content/browser/child_process_security_policy_impl.h" 13 #include "content/browser/child_process_security_policy_impl.h"
14 #include "content/browser/fileapi/browser_file_system_helper.h" 14 #include "content/browser/fileapi/browser_file_system_helper.h"
15 #include "content/common/fileapi/webblob_messages.h" 15 #include "content/common/fileapi/webblob_messages.h"
16 #include "ipc/ipc_platform_file.h" 16 #include "ipc/ipc_platform_file.h"
17 #include "storage/browser/blob/blob_data_handle.h"
18 #include "storage/browser/blob/blob_entry.h"
17 #include "storage/browser/blob/blob_storage_context.h" 19 #include "storage/browser/blob/blob_storage_context.h"
18 #include "storage/browser/blob/blob_transport_result.h"
19 #include "storage/browser/fileapi/file_system_context.h" 20 #include "storage/browser/fileapi/file_system_context.h"
20 #include "storage/browser/fileapi/file_system_url.h" 21 #include "storage/browser/fileapi/file_system_url.h"
21 #include "storage/common/blob_storage/blob_item_bytes_request.h" 22 #include "storage/common/blob_storage/blob_item_bytes_request.h"
22 #include "storage/common/blob_storage/blob_item_bytes_response.h" 23 #include "storage/common/blob_storage/blob_item_bytes_response.h"
23 #include "storage/common/data_element.h" 24 #include "storage/common/data_element.h"
24 #include "url/gurl.h" 25 #include "url/gurl.h"
25 26
26 using storage::BlobStorageContext; 27 using storage::BlobStorageContext;
27 using storage::BlobStorageRegistry; 28 using storage::BlobStorageRegistry;
28 using storage::BlobTransportResult; 29 using storage::BlobStatus;
29 using storage::DataElement; 30 using storage::DataElement;
30 using storage::IPCBlobCreationCancelCode;
31 using storage::FileSystemURL; 31 using storage::FileSystemURL;
32 32
33 namespace content { 33 namespace content {
34 namespace { 34 namespace {
35 using storage::BlobStorageContext;
36 using storage::BlobStorageRegistry;
37 using storage::BlobStatus;
38 using storage::DataElement;
39 using storage::FileSystemURL;
35 40
36 // These are used for UMA stats, don't change. 41 // These are used for UMA stats, don't change.
37 enum RefcountOperation { 42 enum RefcountOperation {
38 BDH_DECREMENT = 0, 43 BDH_DECREMENT = 0,
39 BDH_INCREMENT, 44 BDH_INCREMENT,
40 BDH_TRACING_ENUM_LAST 45 BDH_TRACING_ENUM_LAST
41 }; 46 };
42 47
43 } // namespace 48 } // namespace
44 49
50 BlobDispatcherHost::HostedBlobState::HostedBlobState(
51 std::unique_ptr<storage::BlobDataHandle> handle)
52 : handle(std::move(handle)) {}
53 BlobDispatcherHost::HostedBlobState::~HostedBlobState() {}
54
55 BlobDispatcherHost::HostedBlobState::HostedBlobState(HostedBlobState&&) =
56 default;
57 BlobDispatcherHost::HostedBlobState& BlobDispatcherHost::HostedBlobState::
58 operator=(BlobDispatcherHost::HostedBlobState&&) = default;
59
45 BlobDispatcherHost::BlobDispatcherHost( 60 BlobDispatcherHost::BlobDispatcherHost(
46 int process_id, 61 int process_id,
47 scoped_refptr<ChromeBlobStorageContext> blob_storage_context, 62 scoped_refptr<ChromeBlobStorageContext> blob_storage_context,
48 scoped_refptr<storage::FileSystemContext> file_system_context) 63 scoped_refptr<storage::FileSystemContext> file_system_context)
49 : BrowserMessageFilter(BlobMsgStart), 64 : BrowserMessageFilter(BlobMsgStart),
50 process_id_(process_id), 65 process_id_(process_id),
51 file_system_context_(std::move(file_system_context)), 66 file_system_context_(std::move(file_system_context)),
52 blob_storage_context_(std::move(blob_storage_context)) {} 67 blob_storage_context_(std::move(blob_storage_context)) {}
53 68
54 BlobDispatcherHost::~BlobDispatcherHost() { 69 BlobDispatcherHost::~BlobDispatcherHost() {
55 ClearHostFromBlobStorageContext(); 70 ClearHostFromBlobStorageContext();
56 } 71 }
57 72
58 void BlobDispatcherHost::OnChannelClosing() { 73 void BlobDispatcherHost::OnChannelClosing() {
59 ClearHostFromBlobStorageContext(); 74 ClearHostFromBlobStorageContext();
60 public_blob_urls_.clear(); 75 public_blob_urls_.clear();
61 blobs_inuse_map_.clear(); 76 blobs_inuse_map_.clear();
62 } 77 }
63 78
64 bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message) { 79 bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message) {
65 bool handled = true; 80 bool handled = true;
81 // Note: The only time a renderer sends a blob status message is to cancel.
66 IPC_BEGIN_MESSAGE_MAP(BlobDispatcherHost, message) 82 IPC_BEGIN_MESSAGE_MAP(BlobDispatcherHost, message)
67 IPC_MESSAGE_HANDLER(BlobStorageMsg_RegisterBlobUUID, OnRegisterBlobUUID) 83 IPC_MESSAGE_HANDLER(BlobStorageMsg_RegisterBlob, OnRegisterBlob)
68 IPC_MESSAGE_HANDLER(BlobStorageMsg_StartBuildingBlob, OnStartBuildingBlob)
69 IPC_MESSAGE_HANDLER(BlobStorageMsg_MemoryItemResponse, OnMemoryItemResponse) 84 IPC_MESSAGE_HANDLER(BlobStorageMsg_MemoryItemResponse, OnMemoryItemResponse)
70 IPC_MESSAGE_HANDLER(BlobStorageMsg_CancelBuildingBlob, OnCancelBuildingBlob) 85 IPC_MESSAGE_HANDLER(BlobStorageMsg_SendBlobStatus, OnCancelBuildingBlob)
71 IPC_MESSAGE_HANDLER(BlobHostMsg_IncrementRefCount, OnIncrementBlobRefCount) 86 IPC_MESSAGE_HANDLER(BlobHostMsg_IncrementRefCount, OnIncrementBlobRefCount)
72 IPC_MESSAGE_HANDLER(BlobHostMsg_DecrementRefCount, OnDecrementBlobRefCount) 87 IPC_MESSAGE_HANDLER(BlobHostMsg_DecrementRefCount, OnDecrementBlobRefCount)
73 IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL, OnRegisterPublicBlobURL) 88 IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL, OnRegisterPublicBlobURL)
74 IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL) 89 IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL)
75 IPC_MESSAGE_UNHANDLED(handled = false) 90 IPC_MESSAGE_UNHANDLED(handled = false)
76 IPC_END_MESSAGE_MAP() 91 IPC_END_MESSAGE_MAP()
77 return handled; 92 return handled;
78 } 93 }
79 94
80 void BlobDispatcherHost::OnRegisterBlobUUID( 95 void BlobDispatcherHost::OnRegisterBlob(
81 const std::string& uuid, 96 const std::string& uuid,
82 const std::string& content_type, 97 const std::string& content_type,
83 const std::string& content_disposition, 98 const std::string& content_disposition,
84 const std::set<std::string>& referenced_blob_uuids) { 99 const std::vector<storage::DataElement>& descriptions) {
85 DCHECK_CURRENTLY_ON(BrowserThread::IO); 100 DCHECK_CURRENTLY_ON(BrowserThread::IO);
86 BlobStorageContext* context = this->context(); 101 BlobStorageContext* context = this->context();
87 if (uuid.empty() || context->registry().HasEntry(uuid) || 102 if (uuid.empty() || context->registry().HasEntry(uuid) ||
88 async_builder_.IsBeingBuilt(uuid)) { 103 transport_host_.IsBeingBuilt(uuid)) {
89 bad_message::ReceivedBadMessage(this, bad_message::BDH_UUID_REGISTERED); 104 bad_message::ReceivedBadMessage(this, bad_message::BDH_UUID_REGISTERED);
90 return; 105 return;
91 } 106 }
92 blobs_inuse_map_[uuid] = 1;
93 BlobTransportResult result = async_builder_.RegisterBlobUUID(
94 uuid, content_type, content_disposition, referenced_blob_uuids, context);
95 switch (result) {
96 case BlobTransportResult::BAD_IPC:
97 blobs_inuse_map_.erase(uuid);
98 bad_message::ReceivedBadMessage(this,
99 bad_message::BDH_CONSTRUCTION_FAILED);
100 break;
101 case BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN:
102 // The async builder builds the blob as broken, and we just need to send
103 // the cancel message back to the renderer.
104 Send(new BlobStorageMsg_CancelBuildingBlob(
105 uuid, IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN));
106 break;
107 case BlobTransportResult::DONE:
108 break;
109 case BlobTransportResult::CANCEL_MEMORY_FULL:
110 case BlobTransportResult::CANCEL_FILE_ERROR:
111 case BlobTransportResult::CANCEL_UNKNOWN:
112 case BlobTransportResult::PENDING_RESPONSES:
113 NOTREACHED();
114 break;
115 }
116 }
117 107
118 void BlobDispatcherHost::OnStartBuildingBlob( 108 DCHECK(!base::ContainsKey(blobs_inuse_map_, uuid));
119 const std::string& uuid,
120 const std::vector<storage::DataElement>& descriptions) {
121 DCHECK_CURRENTLY_ON(BrowserThread::IO);
122 if (uuid.empty()) {
123 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC);
124 return;
125 }
126 BlobStorageContext* context = this->context();
127 const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid);
128 if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) {
129 // We ignore messages for blobs that don't exist to handle the case where
130 // the renderer de-refs a blob that we're still constructing, and there are
131 // no references to that blob. We ignore broken as well, in the case where
132 // we decided to break a blob after RegisterBlobUUID is called.
133 // Second, if the last dereference of the blob happened on a different host,
134 // then we still haven't gotten rid of the 'building' state in the original
135 // host. So we call cancel, and send the message just in case that happens.
136 if (async_builder_.IsBeingBuilt(uuid)) {
137 async_builder_.CancelBuildingBlob(
138 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING,
139 context);
140 Send(new BlobStorageMsg_CancelBuildingBlob(
141 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING));
142 }
143 return;
144 }
145 if (!async_builder_.IsBeingBuilt(uuid)) {
146 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC);
147 return;
148 }
149 109
150 ChildProcessSecurityPolicyImpl* security_policy = 110 ChildProcessSecurityPolicyImpl* security_policy =
151 ChildProcessSecurityPolicyImpl::GetInstance(); 111 ChildProcessSecurityPolicyImpl::GetInstance();
152 for (const DataElement& item : descriptions) { 112 for (const DataElement& item : descriptions) {
153 // For each source object that provides the data for the blob, ensure that 113 // For each source object that provides the data for the blob, ensure that
154 // this process has permission to read it. 114 // this process has permission to read it.
155 switch (item.type()) { 115 switch (item.type()) {
156 case storage::DataElement::TYPE_FILE_FILESYSTEM: { 116 case storage::DataElement::TYPE_FILE_FILESYSTEM: {
157 FileSystemURL filesystem_url( 117 FileSystemURL filesystem_url(
158 file_system_context_->CrackURL(item.filesystem_url())); 118 file_system_context_->CrackURL(item.filesystem_url()));
159 if (!FileSystemURLIsValid(file_system_context_.get(), filesystem_url) || 119 if (!FileSystemURLIsValid(file_system_context_.get(), filesystem_url) ||
160 !security_policy->CanReadFileSystemFile(process_id_, 120 !security_policy->CanReadFileSystemFile(process_id_,
161 filesystem_url)) { 121 filesystem_url)) {
162 async_builder_.CancelBuildingBlob( 122 HostedBlobState hosted_state(
163 uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED, context); 123 context->AddBrokenBlob(uuid, content_type, content_disposition,
164 Send(new BlobStorageMsg_CancelBuildingBlob( 124 BlobStatus::ERR_FILE_WRITE_FAILED));
165 uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED)); 125 blobs_inuse_map_.insert(
126 std::make_pair(uuid, std::move(hosted_state)));
127 SendFinalBlobStatus(uuid, BlobStatus::ERR_FILE_WRITE_FAILED);
166 return; 128 return;
167 } 129 }
168 break; 130 break;
169 } 131 }
170 case storage::DataElement::TYPE_FILE: { 132 case storage::DataElement::TYPE_FILE: {
171 if (!security_policy->CanReadFile(process_id_, item.path())) { 133 if (!security_policy->CanReadFile(process_id_, item.path())) {
172 async_builder_.CancelBuildingBlob( 134 HostedBlobState hosted_state(
173 uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED, context); 135 context->AddBrokenBlob(uuid, content_type, content_disposition,
174 Send(new BlobStorageMsg_CancelBuildingBlob( 136 BlobStatus::ERR_FILE_WRITE_FAILED));
175 uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED)); 137 blobs_inuse_map_.insert(
138 std::make_pair(uuid, std::move(hosted_state)));
139 SendFinalBlobStatus(uuid, BlobStatus::ERR_FILE_WRITE_FAILED);
176 return; 140 return;
177 } 141 }
178 break; 142 break;
179 } 143 }
180 case storage::DataElement::TYPE_BLOB: 144 case storage::DataElement::TYPE_BLOB:
181 case storage::DataElement::TYPE_BYTES_DESCRIPTION: 145 case storage::DataElement::TYPE_BYTES_DESCRIPTION:
182 case storage::DataElement::TYPE_BYTES: { 146 case storage::DataElement::TYPE_BYTES: {
183 // Bytes are already in hand; no need to check read permission. 147 // Bytes are already in hand; no need to check read permission.
184 // TODO(nick): For TYPE_BLOB, can we actually get here for blobs 148 // TODO(nick): For TYPE_BLOB, can we actually get here for blobs
185 // originally created by other processes? If so, is that cool? 149 // originally created by other processes? If so, is that cool?
186 break; 150 break;
187 } 151 }
188 case storage::DataElement::TYPE_UNKNOWN: 152 case storage::DataElement::TYPE_UNKNOWN:
189 case storage::DataElement::TYPE_DISK_CACHE_ENTRY: { 153 case storage::DataElement::TYPE_DISK_CACHE_ENTRY: {
190 NOTREACHED(); // Should have been caught by IPC deserialization. 154 NOTREACHED(); // Should have been caught by IPC deserialization.
191 break; 155 break;
192 } 156 }
193 } 157 }
194 } 158 }
195 159
196 // |this| owns async_builder_ so using base::Unretained(this) is safe. 160 HostedBlobState hosted_state(transport_host_.StartBuildingBlob(
197 BlobTransportResult result = async_builder_.StartBuildingBlob( 161 uuid, content_type, content_disposition, descriptions, context,
198 uuid, descriptions, context->memory_available(), context,
199 base::Bind(&BlobDispatcherHost::SendMemoryRequest, base::Unretained(this), 162 base::Bind(&BlobDispatcherHost::SendMemoryRequest, base::Unretained(this),
200 uuid)); 163 uuid),
201 SendIPCResponse(uuid, result); 164 base::Bind(&BlobDispatcherHost::SendFinalBlobStatus,
165 base::Unretained(this), uuid)));
166 blobs_inuse_map_.insert(std::make_pair(uuid, std::move(hosted_state)));
202 } 167 }
203 168
204 void BlobDispatcherHost::OnMemoryItemResponse( 169 void BlobDispatcherHost::OnMemoryItemResponse(
205 const std::string& uuid, 170 const std::string& uuid,
206 const std::vector<storage::BlobItemBytesResponse>& responses) { 171 const std::vector<storage::BlobItemBytesResponse>& responses) {
207 DCHECK_CURRENTLY_ON(BrowserThread::IO); 172 DCHECK_CURRENTLY_ON(BrowserThread::IO);
208 if (uuid.empty()) { 173 if (uuid.empty()) {
209 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); 174 bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED);
210 return; 175 return;
211 } 176 }
212 BlobStorageContext* context = this->context(); 177 BlobStorageContext* context = this->context();
213 const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); 178 const storage::BlobEntry* entry = context->registry().GetEntry(uuid);
214 if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { 179 if (!entry || BlobStatusIsError(entry->status())) {
215 // We ignore messages for blobs that don't exist to handle the case where 180 // We ignore messages for blobs that don't exist to handle the case where
216 // the renderer de-refs a blob that we're still constructing, and there are 181 // the renderer de-refs a blob that we're still constructing, and there are
217 // no references to that blob. We ignore broken as well, in the case where 182 // no references to that blob. We ignore broken as well, in the case where
218 // we decided to break a blob after sending the memory request. 183 // we decided to break a blob after sending the memory request.
219 // Note: if a blob is broken, then it can't be in the async_builder. 184 // Note: if a blob is broken, then it can't be in the transport_host.
220 // Second, if the last dereference of the blob happened on a different host, 185 // Second, if the last dereference of the blob happened on a different host,
221 // then we still haven't gotten rid of the 'building' state in the original 186 // then we still haven't gotten rid of the 'building' state in the original
222 // host. So we call cancel, and send the message just in case that happens. 187 // host. So we call cancel, and send the message just in case that happens.
223 if (async_builder_.IsBeingBuilt(uuid)) { 188 if (transport_host_.IsBeingBuilt(uuid)) {
224 async_builder_.CancelBuildingBlob( 189 transport_host_.CancelBuildingBlob(
225 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, 190 uuid, BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING, context);
michaeln 2016/11/16 00:55:35 you could use context() directly here and below (a
dmurph 2016/11/16 02:15:28 I'd rather pull it out, so we don't have those as
226 context);
227 Send(new BlobStorageMsg_CancelBuildingBlob(
228 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING));
229 } 191 }
230 return; 192 return;
231 } 193 }
232 if (!async_builder_.IsBeingBuilt(uuid)) { 194 if (!transport_host_.IsBeingBuilt(uuid)) {
233 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); 195 bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED);
234 return; 196 return;
235 } 197 }
236 BlobTransportResult result = 198 transport_host_.OnMemoryResponses(uuid, responses, context);
237 async_builder_.OnMemoryResponses(uuid, responses, context);
238 SendIPCResponse(uuid, result);
239 } 199 }
240 200
241 void BlobDispatcherHost::OnCancelBuildingBlob( 201 void BlobDispatcherHost::OnCancelBuildingBlob(const std::string& uuid,
242 const std::string& uuid, 202 const storage::BlobStatus code) {
243 const storage::IPCBlobCreationCancelCode code) {
244 DCHECK_CURRENTLY_ON(BrowserThread::IO); 203 DCHECK_CURRENTLY_ON(BrowserThread::IO);
245 if (uuid.empty()) { 204 if (uuid.empty()) {
246 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); 205 bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED);
247 return; 206 return;
248 } 207 }
249 BlobStorageContext* context = this->context(); 208 BlobStorageContext* context = this->context();
250 const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid); 209 const storage::BlobEntry* entry = context->registry().GetEntry(uuid);
251 if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) { 210 if (!entry || BlobStatusIsError(entry->status())) {
252 // We ignore messages for blobs that don't exist to handle the case where 211 // We ignore messages for blobs that don't exist to handle the case where
253 // the renderer de-refs a blob that we're still constructing, and there are 212 // the renderer de-refs a blob that we're still constructing, and there are
254 // no references to that blob. We ignore broken as well, in the case where 213 // no references to that blob. We ignore broken as well, in the case where
255 // we decided to break a blob and the renderer also decided to cancel. 214 // we decided to break a blob and the renderer also decided to cancel.
256 // Note: if a blob is broken, then it can't be in the async_builder. 215 // Note: if a blob is broken, then it can't be in the transport_host.
257 // Second, if the last dereference of the blob happened on a different host, 216 // Second, if the last dereference of the blob happened on a different host,
258 // then we still haven't gotten rid of the 'building' state in the original 217 // then we still haven't gotten rid of the 'building' state in the original
259 // host. So we call cancel just in case this happens. 218 // host. So we call cancel just in case this happens.
260 if (async_builder_.IsBeingBuilt(uuid)) { 219 if (transport_host_.IsBeingBuilt(uuid)) {
261 async_builder_.CancelBuildingBlob( 220 transport_host_.CancelBuildingBlob(
262 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, 221 uuid, BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING, context);
263 context);
264 } 222 }
265 return; 223 return;
266 } 224 }
267 if (!async_builder_.IsBeingBuilt(uuid)) { 225 if (!transport_host_.IsBeingBuilt(uuid) ||
268 SendIPCResponse(uuid, BlobTransportResult::BAD_IPC); 226 !storage::BlobStatusIsError(code)) {
227 bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED);
269 return; 228 return;
270 } 229 }
271 VLOG(1) << "Blob construction of " << uuid << " cancelled by renderer. " 230 VLOG(1) << "Blob construction of " << uuid << " cancelled by renderer. "
272 << " Reason: " << static_cast<int>(code) << "."; 231 << " Reason: " << static_cast<int>(code) << ".";
273 async_builder_.CancelBuildingBlob(uuid, code, context); 232 // Note: This will cause SendFinalBlobStatus to be called. This is intentional
233 // to increment the ref count. However we extra IPC message to the renderer,
234 // which will be ignored.
michaeln 2016/11/16 00:55:35 i'm not sure the comment helps here?
dmurph 2016/11/16 02:15:28 Done.
235 transport_host_.CancelBuildingBlob(uuid, code, context);
274 } 236 }
275 237
276 void BlobDispatcherHost::OnIncrementBlobRefCount(const std::string& uuid) { 238 void BlobDispatcherHost::OnIncrementBlobRefCount(const std::string& uuid) {
277 DCHECK_CURRENTLY_ON(BrowserThread::IO); 239 DCHECK_CURRENTLY_ON(BrowserThread::IO);
278 BlobStorageContext* context = this->context(); 240 BlobStorageContext* context = this->context();
279 if (uuid.empty()) { 241 if (uuid.empty()) {
280 bad_message::ReceivedBadMessage( 242 bad_message::ReceivedBadMessage(
281 this, bad_message::BDH_INVALID_REFCOUNT_OPERATION); 243 this, bad_message::BDH_INVALID_REFCOUNT_OPERATION);
282 return; 244 return;
283 } 245 }
284 if (!context->registry().HasEntry(uuid)) { 246 if (!context->registry().HasEntry(uuid)) {
285 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidReference", BDH_INCREMENT, 247 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidReference", BDH_INCREMENT,
286 BDH_TRACING_ENUM_LAST); 248 BDH_TRACING_ENUM_LAST);
287 return; 249 return;
288 } 250 }
289 context->IncrementBlobRefCount(uuid); 251 auto state_it = blobs_inuse_map_.find(uuid);
290 blobs_inuse_map_[uuid] += 1; 252 if (state_it != blobs_inuse_map_.end()) {
253 state_it->second.refcount += 1;
254 return;
255 }
256 blobs_inuse_map_.insert(std::make_pair(
257 uuid, HostedBlobState(context->GetBlobDataFromUUID(uuid))));
291 } 258 }
292 259
293 void BlobDispatcherHost::OnDecrementBlobRefCount(const std::string& uuid) { 260 void BlobDispatcherHost::OnDecrementBlobRefCount(const std::string& uuid) {
294 DCHECK_CURRENTLY_ON(BrowserThread::IO); 261 DCHECK_CURRENTLY_ON(BrowserThread::IO);
295 if (uuid.empty()) { 262 if (uuid.empty()) {
296 bad_message::ReceivedBadMessage( 263 bad_message::ReceivedBadMessage(
297 this, bad_message::BDH_INVALID_REFCOUNT_OPERATION); 264 this, bad_message::BDH_INVALID_REFCOUNT_OPERATION);
298 return; 265 return;
299 } 266 }
300 if (!IsInUseInHost(uuid)) { 267 auto state_it = blobs_inuse_map_.find(uuid);
268 if (state_it == blobs_inuse_map_.end()) {
301 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidReference", BDH_DECREMENT, 269 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidReference", BDH_DECREMENT,
302 BDH_TRACING_ENUM_LAST); 270 BDH_TRACING_ENUM_LAST);
303 return; 271 return;
304 } 272 }
305 BlobStorageContext* context = this->context(); 273 state_it->second.refcount -= 1;
306 context->DecrementBlobRefCount(uuid); 274 if (state_it->second.refcount == 0) {
307 blobs_inuse_map_[uuid] -= 1; 275 blobs_inuse_map_.erase(state_it);
308 if (blobs_inuse_map_[uuid] == 0) { 276
309 blobs_inuse_map_.erase(uuid); 277 // If we're being built still and we don't have any other references, cancel
310 // If the blob has been deleted in the context and we're still building it, 278 // construction.
311 // this means we have no references waiting to read it. Clear the building 279 BlobStorageContext* context = this->context();
312 // state and send a cancel message to the renderer. 280 if (transport_host_.IsBeingBuilt(uuid) &&
313 if (async_builder_.IsBeingBuilt(uuid) &&
314 !context->registry().HasEntry(uuid)) { 281 !context->registry().HasEntry(uuid)) {
315 async_builder_.CancelBuildingBlob( 282 transport_host_.CancelBuildingBlob(
316 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING, 283 uuid, BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING, context);
317 context);
318 Send(new BlobStorageMsg_CancelBuildingBlob(
319 uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING));
320 } 284 }
321 } 285 }
322 } 286 }
323 287
324 void BlobDispatcherHost::OnRegisterPublicBlobURL(const GURL& public_url, 288 void BlobDispatcherHost::OnRegisterPublicBlobURL(const GURL& public_url,
325 const std::string& uuid) { 289 const std::string& uuid) {
326 DCHECK_CURRENTLY_ON(BrowserThread::IO); 290 DCHECK_CURRENTLY_ON(BrowserThread::IO);
327 ChildProcessSecurityPolicyImpl* security_policy = 291 ChildProcessSecurityPolicyImpl* security_policy =
328 ChildProcessSecurityPolicyImpl::GetInstance(); 292 ChildProcessSecurityPolicyImpl::GetInstance();
329 293
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 context()->RevokePublicBlobURL(public_url); 329 context()->RevokePublicBlobURL(public_url);
366 public_blob_urls_.erase(public_url); 330 public_blob_urls_.erase(public_url);
367 } 331 }
368 332
369 storage::BlobStorageContext* BlobDispatcherHost::context() { 333 storage::BlobStorageContext* BlobDispatcherHost::context() {
370 return blob_storage_context_->context(); 334 return blob_storage_context_->context();
371 } 335 }
372 336
373 void BlobDispatcherHost::SendMemoryRequest( 337 void BlobDispatcherHost::SendMemoryRequest(
374 const std::string& uuid, 338 const std::string& uuid,
375 std::unique_ptr<std::vector<storage::BlobItemBytesRequest>> requests, 339 std::vector<storage::BlobItemBytesRequest> requests,
376 std::unique_ptr<std::vector<base::SharedMemoryHandle>> memory_handles, 340 std::vector<base::SharedMemoryHandle> memory_handles,
377 std::unique_ptr<std::vector<base::File>> files) { 341 std::vector<base::File> files) {
378 DCHECK_CURRENTLY_ON(BrowserThread::IO); 342 DCHECK_CURRENTLY_ON(BrowserThread::IO);
379 std::vector<IPC::PlatformFileForTransit> file_handles; 343 std::vector<IPC::PlatformFileForTransit> file_handles;
380 // TODO(dmurph): Support file-backed blob transportation. 344 for (base::File& file : files) {
381 DCHECK(files->empty()); 345 file_handles.push_back(IPC::TakePlatformFileForTransit(std::move(file)));
382 Send(new BlobStorageMsg_RequestMemoryItem(uuid, *requests, *memory_handles, 346 }
347 Send(new BlobStorageMsg_RequestMemoryItem(uuid, requests, memory_handles,
383 file_handles)); 348 file_handles));
384 } 349 }
385 350
386 void BlobDispatcherHost::SendIPCResponse(const std::string& uuid, 351 void BlobDispatcherHost::SendFinalBlobStatus(const std::string& uuid,
387 storage::BlobTransportResult result) { 352 BlobStatus status) {
388 switch (result) { 353 DCHECK(!BlobStatusIsPending(status));
389 case BlobTransportResult::BAD_IPC: 354 if (storage::BlobStatusIsBadIPC(status)) {
390 bad_message::ReceivedBadMessage(this, 355 bad_message::ReceivedBadMessage(this, bad_message::BDH_CONSTRUCTION_FAILED);
391 bad_message::BDH_CONSTRUCTION_FAILED);
392 return;
393 case BlobTransportResult::CANCEL_MEMORY_FULL:
394 Send(new BlobStorageMsg_CancelBuildingBlob(
395 uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY));
396 return;
397 case BlobTransportResult::CANCEL_FILE_ERROR:
398 Send(new BlobStorageMsg_CancelBuildingBlob(
399 uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED));
400 return;
401 case BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN:
402 Send(new BlobStorageMsg_CancelBuildingBlob(
403 uuid, IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN));
404 return;
405 case BlobTransportResult::CANCEL_UNKNOWN:
406 Send(new BlobStorageMsg_CancelBuildingBlob(
407 uuid, IPCBlobCreationCancelCode::UNKNOWN));
408 return;
409 case BlobTransportResult::PENDING_RESPONSES:
410 return;
411 case BlobTransportResult::DONE:
412 Send(new BlobStorageMsg_DoneBuildingBlob(uuid));
413 return;
414 } 356 }
415 NOTREACHED(); 357 Send(new BlobStorageMsg_SendBlobStatus(uuid, status));
416 } 358 }
417 359
418 bool BlobDispatcherHost::IsInUseInHost(const std::string& uuid) { 360 bool BlobDispatcherHost::IsInUseInHost(const std::string& uuid) {
419 return blobs_inuse_map_.find(uuid) != blobs_inuse_map_.end(); 361 return base::ContainsKey(blobs_inuse_map_, uuid);
420 } 362 }
421 363
422 bool BlobDispatcherHost::IsUrlRegisteredInHost(const GURL& blob_url) { 364 bool BlobDispatcherHost::IsUrlRegisteredInHost(const GURL& blob_url) {
423 return public_blob_urls_.find(blob_url) != public_blob_urls_.end(); 365 return base::ContainsKey(public_blob_urls_, blob_url);
424 } 366 }
425 367
426 void BlobDispatcherHost::ClearHostFromBlobStorageContext() { 368 void BlobDispatcherHost::ClearHostFromBlobStorageContext() {
427 BlobStorageContext* context = this->context(); 369 BlobStorageContext* context = this->context();
428 for (const auto& url : public_blob_urls_) { 370 for (const auto& url : public_blob_urls_) {
429 context->RevokePublicBlobURL(url); 371 context->RevokePublicBlobURL(url);
430 } 372 }
431 for (const auto& uuid_refnum_pair : blobs_inuse_map_) { 373 // Keep the blobs alive for the BlobTransportHost call.
432 for (int i = 0; i < uuid_refnum_pair.second; ++i) 374 transport_host_.CancelAll(context);
433 context->DecrementBlobRefCount(uuid_refnum_pair.first); 375 blobs_inuse_map_.clear();
434 }
435 async_builder_.CancelAll(context);
436 } 376 }
437 377
438 } // namespace content 378 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698