OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/browser/download/download_file_manager.h" | 5 #include "chrome/browser/download/download_file_manager.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/task.h" | 10 #include "base/task.h" |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 // DownloadFile has been deleted. | 162 // DownloadFile has been deleted. |
163 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { | 163 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { |
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
165 std::vector<DownloadBuffer::Contents> contents; | 165 std::vector<DownloadBuffer::Contents> contents; |
166 { | 166 { |
167 base::AutoLock auto_lock(buffer->lock); | 167 base::AutoLock auto_lock(buffer->lock); |
168 contents.swap(buffer->contents); | 168 contents.swap(buffer->contents); |
169 } | 169 } |
170 | 170 |
171 DownloadFile* download_file = GetDownloadFile(id); | 171 DownloadFile* download_file = GetDownloadFile(id); |
172 bool had_error = false; | |
172 for (size_t i = 0; i < contents.size(); ++i) { | 173 for (size_t i = 0; i < contents.size(); ++i) { |
173 net::IOBuffer* data = contents[i].first; | 174 net::IOBuffer* data = contents[i].first; |
174 const int data_len = contents[i].second; | 175 const int data_len = contents[i].second; |
175 if (download_file) | 176 if (!had_error && download_file) { |
176 download_file->AppendDataToFile(data->data(), data_len); | 177 bool write_succeeded = |
cbentzel
2011/08/16 15:50:36
If this is going to end up with a net_error code r
ahendrickson
2011/08/18 21:52:01
AppendDataToFile() returns a bool currently. Anot
| |
178 download_file->AppendDataToFile(data->data(), data_len); | |
179 if (!write_succeeded) { | |
180 // Write failed: interrupt the download. | |
181 std::string hash; | |
182 DownloadManager* download_manager = download_file->GetDownloadManager(); | |
183 had_error = true; | |
184 | |
185 // Calling this here in case we get more data, to avoid calling | |
186 // |OnDownloadError()| more than once. | |
187 CancelDownload(id); | |
cbentzel
2011/08/16 15:50:36
BUG: I'm not sure the CancelDownload is right.
a]
ahendrickson
2011/08/18 21:52:01
Fixed. Now get the number of bytes before canceli
cbentzel
2011/08/19 13:02:41
What race condition?
I agree that calling CancelD
ahendrickson
2011/08/19 18:11:59
Hmm, I misspoke a bit, I think. We might not make
| |
188 | |
189 if (download_manager) { | |
190 BrowserThread::PostTask( | |
191 BrowserThread::UI, | |
192 FROM_HERE, | |
193 NewRunnableMethod( | |
194 download_manager, | |
195 &DownloadManager::OnDownloadError, | |
196 id, | |
197 download_file->bytes_so_far(), | |
198 net::ERR_FAILED)); | |
199 } | |
200 } | |
201 } | |
177 data->Release(); | 202 data->Release(); |
178 } | 203 } |
179 } | 204 } |
180 | 205 |
181 void DownloadFileManager::OnResponseCompleted( | 206 void DownloadFileManager::OnResponseCompleted( |
182 int id, | 207 int id, |
183 DownloadBuffer* buffer, | 208 DownloadBuffer* buffer, |
184 int os_error, | 209 int net_error, |
185 const std::string& security_info) { | 210 const std::string& security_info) { |
186 VLOG(20) << __FUNCTION__ << "()" << " id = " << id | 211 VLOG(20) << __FUNCTION__ << "()" << " id = " << id |
187 << " os_error = " << os_error | 212 << " net_error = " << net_error |
188 << " security_info = \"" << security_info << "\""; | 213 << " security_info = \"" << security_info << "\""; |
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
190 delete buffer; | 215 delete buffer; |
191 DownloadFile* download_file = GetDownloadFile(id); | 216 DownloadFile* download_file = GetDownloadFile(id); |
192 if (!download_file) | 217 if (!download_file) |
193 return; | 218 return; |
194 | 219 |
195 download_file->Finish(); | 220 download_file->Finish(); |
196 | 221 |
197 DownloadManager* download_manager = download_file->GetDownloadManager(); | 222 DownloadManager* download_manager = download_file->GetDownloadManager(); |
198 if (!download_manager) { | 223 if (!download_manager) { |
199 CancelDownload(id); | 224 CancelDownload(id); |
200 return; | 225 return; |
201 } | 226 } |
202 | 227 |
203 std::string hash; | 228 std::string hash; |
204 if (!download_file->GetSha256Hash(&hash)) | 229 if (!download_file->GetSha256Hash(&hash)) |
205 hash.clear(); | 230 hash.clear(); |
206 | 231 |
207 BrowserThread::PostTask( | 232 // ERR_CONNECTION_CLOSED is allowed since a number of servers in the wild |
208 BrowserThread::UI, FROM_HERE, | 233 // advertise a larger Content-Length than the amount of bytes in the message |
209 NewRunnableMethod( | 234 // body, and then close the connection. Other browsers - IE8, Firefox 4.0.1, |
210 download_manager, &DownloadManager::OnResponseCompleted, | 235 // and Safari 5.0.4 - treat the download as complete in this case, so we |
211 id, download_file->bytes_so_far(), os_error, hash)); | 236 // follow their lead. |
237 if (net_error == net::OK || net_error == net::ERR_CONNECTION_CLOSED) { | |
238 BrowserThread::PostTask( | |
239 BrowserThread::UI, | |
240 FROM_HERE, | |
241 NewRunnableMethod( | |
242 download_manager, | |
243 &DownloadManager::OnResponseCompleted, | |
244 id, | |
245 download_file->bytes_so_far(), | |
246 hash)); | |
247 } else { | |
248 BrowserThread::PostTask( | |
249 BrowserThread::UI, | |
250 FROM_HERE, | |
251 NewRunnableMethod( | |
252 download_manager, | |
253 &DownloadManager::OnDownloadError, | |
254 id, | |
255 download_file->bytes_so_far(), | |
256 net_error)); | |
257 } | |
212 // We need to keep the download around until the UI thread has finalized | 258 // We need to keep the download around until the UI thread has finalized |
213 // the name. | 259 // the name. |
214 } | 260 } |
215 | 261 |
216 // This method will be sent via a user action, or shutdown on the UI thread, and | 262 // This method will be sent via a user action, or shutdown on the UI thread, and |
217 // run on the download thread. Since this message has been sent from the UI | 263 // run on the download thread. Since this message has been sent from the UI |
218 // thread, the download may have already completed and won't exist in our map. | 264 // thread, the download may have already completed and won't exist in our map. |
219 void DownloadFileManager::CancelDownload(int id) { | 265 void DownloadFileManager::CancelDownload(int id) { |
220 VLOG(20) << __FUNCTION__ << "()" << " id = " << id; | 266 VLOG(20) << __FUNCTION__ << "()" << " id = " << id; |
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
287 DownloadFile* download_file = GetDownloadFile(id); | 333 DownloadFile* download_file = GetDownloadFile(id); |
288 if (!download_file) | 334 if (!download_file) |
289 return; | 335 return; |
290 | 336 |
291 VLOG(20) << __FUNCTION__ << "()" | 337 VLOG(20) << __FUNCTION__ << "()" |
292 << " download_file = " << download_file->DebugString(); | 338 << " download_file = " << download_file->DebugString(); |
293 | 339 |
294 if (!download_file->Rename(full_path)) { | 340 if (!download_file->Rename(full_path)) { |
295 // Error. Between the time the UI thread generated 'full_path' to the time | 341 // Error. Between the time the UI thread generated 'full_path' to the time |
296 // this code runs, something happened that prevents us from renaming. | 342 // this code runs, something happened that prevents us from renaming. |
297 CancelDownloadOnRename(id); | 343 CancelDownloadOnRename(id, net::ERR_FAILED); |
298 } | 344 } |
299 } | 345 } |
300 | 346 |
301 // The DownloadManager in the UI thread has provided a final name for the | 347 // The DownloadManager in the UI thread has provided a final name for the |
302 // download specified by 'id'. Rename the download that's in the process | 348 // download specified by 'id'. Rename the download that's in the process |
303 // of completing. | 349 // of completing. |
304 // | 350 // |
305 // There are 2 possible rename cases where this method can be called: | 351 // There are 2 possible rename cases where this method can be called: |
306 // 1. foo.crdownload -> foo (final, safe) | 352 // 1. foo.crdownload -> foo (final, safe) |
307 // 2. Unconfirmed.xxx.crdownload -> xxx (final, validated) | 353 // 2. Unconfirmed.xxx.crdownload -> xxx (final, validated) |
(...skipping 27 matching lines...) Expand all Loading... | |
335 uniquifier = download_util::GetUniquePathNumber(new_path); | 381 uniquifier = download_util::GetUniquePathNumber(new_path); |
336 if (uniquifier > 0) { | 382 if (uniquifier > 0) { |
337 download_util::AppendNumberToPath(&new_path, uniquifier); | 383 download_util::AppendNumberToPath(&new_path, uniquifier); |
338 } | 384 } |
339 } | 385 } |
340 | 386 |
341 // Rename the file, overwriting if necessary. | 387 // Rename the file, overwriting if necessary. |
342 if (!download_file->Rename(new_path)) { | 388 if (!download_file->Rename(new_path)) { |
343 // Error. Between the time the UI thread generated 'full_path' to the time | 389 // Error. Between the time the UI thread generated 'full_path' to the time |
344 // this code runs, something happened that prevents us from renaming. | 390 // this code runs, something happened that prevents us from renaming. |
345 CancelDownloadOnRename(id); | 391 CancelDownloadOnRename(id, net::ERR_FAILED); |
346 return; | 392 return; |
347 } | 393 } |
348 | 394 |
349 #if defined(OS_MACOSX) | 395 #if defined(OS_MACOSX) |
350 // Done here because we only want to do this once; see | 396 // Done here because we only want to do this once; see |
351 // http://crbug.com/13120 for details. | 397 // http://crbug.com/13120 for details. |
352 download_file->AnnotateWithSourceInformation(); | 398 download_file->AnnotateWithSourceInformation(); |
353 #endif | 399 #endif |
354 | 400 |
355 BrowserThread::PostTask( | 401 BrowserThread::PostTask( |
356 BrowserThread::UI, FROM_HERE, | 402 BrowserThread::UI, FROM_HERE, |
357 NewRunnableMethod( | 403 NewRunnableMethod( |
358 download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id, | 404 download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id, |
359 new_path, uniquifier)); | 405 new_path, uniquifier)); |
360 } | 406 } |
361 | 407 |
362 // Called only from RenameInProgressDownloadFile and | 408 // Called only from RenameInProgressDownloadFile and |
363 // RenameCompletingDownloadFile on the FILE thread. | 409 // RenameCompletingDownloadFile on the FILE thread. |
364 void DownloadFileManager::CancelDownloadOnRename(int id) { | 410 void DownloadFileManager::CancelDownloadOnRename(int id, int rename_error) { |
365 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
366 | 412 |
367 DownloadFile* download_file = GetDownloadFile(id); | 413 DownloadFile* download_file = GetDownloadFile(id); |
368 if (!download_file) | 414 if (!download_file) |
369 return; | 415 return; |
370 | 416 |
371 DownloadManager* download_manager = download_file->GetDownloadManager(); | 417 DownloadManager* download_manager = download_file->GetDownloadManager(); |
372 if (!download_manager) { | 418 if (!download_manager) { |
373 // Without a download manager, we can't cancel the request normally, so we | 419 // Without a download manager, we can't cancel the request normally, so we |
374 // need to do it here. The normal path will also update the download | 420 // need to do it here. The normal path will also update the download |
375 // history before cancelling the request. | 421 // history before canceling the request. |
376 download_file->CancelDownloadRequest(); | 422 download_file->CancelDownloadRequest(); |
377 return; | 423 return; |
378 } | 424 } |
379 | 425 |
380 BrowserThread::PostTask( | 426 BrowserThread::PostTask( |
381 BrowserThread::UI, FROM_HERE, | 427 BrowserThread::UI, FROM_HERE, |
382 NewRunnableMethod(download_manager, | 428 NewRunnableMethod(download_manager, |
383 &DownloadManager::DownloadCancelled, id)); | 429 &DownloadManager::OnDownloadError, |
430 id, | |
431 download_file->bytes_so_far(), | |
432 rename_error)); | |
384 } | 433 } |
385 | 434 |
386 void DownloadFileManager::EraseDownload(int id) { | 435 void DownloadFileManager::EraseDownload(int id) { |
387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 436 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
388 | 437 |
389 if (!ContainsKey(downloads_, id)) | 438 if (!ContainsKey(downloads_, id)) |
390 return; | 439 return; |
391 | 440 |
392 DownloadFile* download_file = downloads_[id]; | 441 DownloadFile* download_file = downloads_[id]; |
393 | 442 |
394 VLOG(20) << " " << __FUNCTION__ << "()" | 443 VLOG(20) << " " << __FUNCTION__ << "()" |
395 << " id = " << id | 444 << " id = " << id |
396 << " download_file = " << download_file->DebugString(); | 445 << " download_file = " << download_file->DebugString(); |
397 | 446 |
398 downloads_.erase(id); | 447 downloads_.erase(id); |
399 | 448 |
400 delete download_file; | 449 delete download_file; |
401 | 450 |
402 if (downloads_.empty()) | 451 if (downloads_.empty()) |
403 StopUpdateTimer(); | 452 StopUpdateTimer(); |
404 } | 453 } |
OLD | NEW |