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 |