OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/download/download_item_impl.h" | 5 #include "content/browser/download/download_item_impl.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/format_macros.h" | 12 #include "base/format_macros.h" |
13 #include "base/i18n/case_conversion.h" | 13 #include "base/i18n/case_conversion.h" |
14 #include "base/i18n/string_search.h" | 14 #include "base/i18n/string_search.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/stringprintf.h" | 18 #include "base/stringprintf.h" |
19 #include "base/utf_string_conversions.h" | 19 #include "base/utf_string_conversions.h" |
20 #include "content/browser/download/download_create_info.h" | 20 #include "content/browser/download/download_create_info.h" |
21 #include "content/browser/download/download_file.h" | 21 #include "content/browser/download/download_file.h" |
22 #include "content/browser/download/download_file_manager.h" | |
23 #include "content/browser/download/download_interrupt_reasons_impl.h" | 22 #include "content/browser/download/download_interrupt_reasons_impl.h" |
24 #include "content/browser/download/download_item_impl_delegate.h" | 23 #include "content/browser/download/download_item_impl_delegate.h" |
25 #include "content/browser/download/download_request_handle.h" | 24 #include "content/browser/download/download_request_handle.h" |
26 #include "content/browser/download/download_stats.h" | 25 #include "content/browser/download/download_stats.h" |
27 #include "content/browser/web_contents/web_contents_impl.h" | 26 #include "content/browser/web_contents/web_contents_impl.h" |
28 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" |
29 #include "content/public/browser/content_browser_client.h" | 28 #include "content/public/browser/content_browser_client.h" |
30 #include "content/public/browser/download_persistent_store_info.h" | 29 #include "content/public/browser/download_persistent_store_info.h" |
31 #include "net/base/net_util.h" | 30 #include "net/base/net_util.h" |
32 | 31 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 return NULL; | 111 return NULL; |
113 } | 112 } |
114 virtual void PauseRequest() const OVERRIDE {} | 113 virtual void PauseRequest() const OVERRIDE {} |
115 virtual void ResumeRequest() const OVERRIDE {} | 114 virtual void ResumeRequest() const OVERRIDE {} |
116 virtual void CancelRequest() const OVERRIDE {} | 115 virtual void CancelRequest() const OVERRIDE {} |
117 virtual std::string DebugString() const OVERRIDE { | 116 virtual std::string DebugString() const OVERRIDE { |
118 return "Null DownloadRequestHandle"; | 117 return "Null DownloadRequestHandle"; |
119 } | 118 } |
120 }; | 119 }; |
121 | 120 |
| 121 // Detach the specified download file, then invoke the callback on the |
| 122 // UI thread. Note that this will also delete the DownloadFile object, |
| 123 // as the function accepts ownership and does not transfer it on. |
| 124 // |
| 125 // This is effectively a "PostTaskAndReply" targeted at |
| 126 // download_file->Detach(), with the difference that the destruction of the |
| 127 // task arguments is done on the target thread rather than the originating |
| 128 // thread. If |ui_callback| wasn't needed, we could have just used |
| 129 // PostTask transferring ownership of download_file, and if download_file |
| 130 // FILE thread destruction wasn't needed, we could have used PostTaskAndReply. |
| 131 static void ReleaseDownloadFile(scoped_ptr<DownloadFile> download_file, |
| 132 const base::Closure& ui_callback) { |
| 133 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 134 download_file->Detach(); |
| 135 |
| 136 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, ui_callback); |
| 137 } |
| 138 |
122 } // namespace | 139 } // namespace |
123 | 140 |
124 namespace content { | 141 namespace content { |
125 | 142 |
126 // Our download table ID starts at 1, so we use 0 to represent a download that | 143 // Our download table ID starts at 1, so we use 0 to represent a download that |
127 // has started, but has not yet had its data persisted in the table. We use fake | 144 // has started, but has not yet had its data persisted in the table. We use fake |
128 // database handles in incognito mode starting at -1 and progressively getting | 145 // database handles in incognito mode starting at -1 and progressively getting |
129 // more negative. | 146 // more negative. |
130 // static | 147 // static |
131 const int DownloadItem::kUninitializedHandle = 0; | 148 const int DownloadItem::kUninitializedHandle = 0; |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 delegate_delayed_complete_(false), | 307 delegate_delayed_complete_(false), |
291 bound_net_log_(bound_net_log), | 308 bound_net_log_(bound_net_log), |
292 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | 309 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
293 delegate_->Attach(); | 310 delegate_->Attach(); |
294 Init(true /* actively downloading */, | 311 Init(true /* actively downloading */, |
295 download_net_logs::SRC_SAVE_PAGE_AS); | 312 download_net_logs::SRC_SAVE_PAGE_AS); |
296 } | 313 } |
297 | 314 |
298 DownloadItemImpl::~DownloadItemImpl() { | 315 DownloadItemImpl::~DownloadItemImpl() { |
299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 317 |
| 318 // Should always have been nuked before now, at worst in |
| 319 // DownloadManager shutdown. |
| 320 DCHECK(!download_file_.get()); |
| 321 |
300 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this)); | 322 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this)); |
301 delegate_->AssertStateConsistent(this); | 323 delegate_->AssertStateConsistent(this); |
302 delegate_->Detach(); | 324 delegate_->Detach(); |
303 } | 325 } |
304 | 326 |
| 327 base::WeakPtr<content::DownloadDestinationObserver> |
| 328 DownloadItemImpl::DestinationObserverAsWeakPtr() { |
| 329 // Return does private downcast. |
| 330 return weak_ptr_factory_.GetWeakPtr(); |
| 331 } |
| 332 |
305 void DownloadItemImpl::AddObserver(Observer* observer) { | 333 void DownloadItemImpl::AddObserver(Observer* observer) { |
306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
307 | 335 |
308 observers_.AddObserver(observer); | 336 observers_.AddObserver(observer); |
309 } | 337 } |
310 | 338 |
311 void DownloadItemImpl::RemoveObserver(Observer* observer) { | 339 void DownloadItemImpl::RemoveObserver(Observer* observer) { |
312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
313 | 341 |
314 observers_.RemoveObserver(observer); | 342 observers_.RemoveObserver(observer); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 bound_net_log_.AddEvent( | 411 bound_net_log_.AddEvent( |
384 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, | 412 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, |
385 base::Bind(&download_net_logs::ItemCheckedCallback, | 413 base::Bind(&download_net_logs::ItemCheckedCallback, |
386 GetDangerType(), GetSafetyState())); | 414 GetDangerType(), GetSafetyState())); |
387 | 415 |
388 UpdateObservers(); | 416 UpdateObservers(); |
389 | 417 |
390 delegate_->MaybeCompleteDownload(this); | 418 delegate_->MaybeCompleteDownload(this); |
391 } | 419 } |
392 | 420 |
393 void DownloadItemImpl::ProgressComplete(int64 bytes_so_far, | |
394 const std::string& final_hash) { | |
395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
396 | |
397 hash_ = final_hash; | |
398 hash_state_ = ""; | |
399 | |
400 received_bytes_ = bytes_so_far; | |
401 | |
402 // If we've received more data than we were expecting (bad server info?), | |
403 // revert to 'unknown size mode'. | |
404 if (received_bytes_ > total_bytes_) | |
405 total_bytes_ = 0; | |
406 } | |
407 | |
408 // Updates from the download thread may have been posted while this download | 421 // Updates from the download thread may have been posted while this download |
409 // was being cancelled in the UI thread, so we'll accept them unless we're | 422 // was being cancelled in the UI thread, so we'll accept them unless we're |
410 // complete. | 423 // complete. |
411 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, | 424 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, |
412 int64 bytes_per_sec, | 425 int64 bytes_per_sec, |
413 const std::string& hash_state) { | 426 const std::string& hash_state) { |
414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
415 | 428 |
416 if (!IsInProgress()) { | 429 if (!IsInProgress()) { |
417 // Ignore if we're no longer in-progress. This can happen if we race a | 430 // Ignore if we're no longer in-progress. This can happen if we race a |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); | 467 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
455 if (!IsPartialDownload()) { | 468 if (!IsPartialDownload()) { |
456 // Small downloads might be complete before this method has | 469 // Small downloads might be complete before this method has |
457 // a chance to run. | 470 // a chance to run. |
458 return; | 471 return; |
459 } | 472 } |
460 | 473 |
461 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); | 474 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); |
462 | 475 |
463 TransitionTo(CANCELLED); | 476 TransitionTo(CANCELLED); |
| 477 |
| 478 // Cancel and remove the download file. |
| 479 DCHECK(download_file_.get()); |
| 480 BrowserThread::PostTask( |
| 481 BrowserThread::FILE, FROM_HERE, |
| 482 // Will be deleted at end of task execution. |
| 483 base::Bind(&DownloadFile::Cancel, base::Owned(download_file_.release()))); |
| 484 |
| 485 // Cancel the originating URL request. |
| 486 request_handle_->CancelRequest(); |
| 487 |
464 if (user_cancel) | 488 if (user_cancel) |
465 delegate_->DownloadStopped(this); | 489 delegate_->DownloadStopped(this); |
466 } | 490 } |
467 | 491 |
| 492 // We're starting the download. |
| 493 void DownloadItemImpl::Start(scoped_ptr<content::DownloadFile> download_file) { |
| 494 DCHECK(!download_file_.get()); |
| 495 download_file_ = download_file.Pass(); |
| 496 |
| 497 BrowserThread::PostTask( |
| 498 BrowserThread::FILE, FROM_HERE, |
| 499 base::Bind(&DownloadFile::Initialize, |
| 500 // Safe because we control download file lifetime. |
| 501 base::Unretained(download_file_.get()), |
| 502 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, |
| 503 weak_ptr_factory_.GetWeakPtr()))); |
| 504 } |
| 505 |
468 // An error occurred somewhere. | 506 // An error occurred somewhere. |
469 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { | 507 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { |
470 // Somewhat counter-intuitively, it is possible for us to receive an | 508 // Somewhat counter-intuitively, it is possible for us to receive an |
471 // interrupt after we've already been interrupted. The generation of | 509 // interrupt after we've already been interrupted. The generation of |
472 // interrupts from the file thread Renames and the generation of | 510 // interrupts from the file thread Renames and the generation of |
473 // interrupts from disk writes go through two different mechanisms (driven | 511 // interrupts from disk writes go through two different mechanisms (driven |
474 // by rename requests from UI thread and by write requests from IO thread, | 512 // by rename requests from UI thread and by write requests from IO thread, |
475 // respectively), and since we choose not to keep state on the File thread, | 513 // respectively), and since we choose not to keep state on the File thread, |
476 // this is the place where the races collide. It's also possible for | 514 // this is the place where the races collide. It's also possible for |
477 // interrupts to race with cancels. | 515 // interrupts to race with cancels. |
478 | 516 |
479 // Whatever happens, the first one to hit the UI thread wins. | 517 // Whatever happens, the first one to hit the UI thread wins. |
480 if (!IsInProgress()) | 518 if (!IsInProgress()) |
481 return; | 519 return; |
482 | 520 |
483 last_reason_ = reason; | 521 last_reason_ = reason; |
484 TransitionTo(INTERRUPTED); | 522 TransitionTo(INTERRUPTED); |
| 523 |
| 524 // Cancel and remove the download file. |
| 525 DCHECK(download_file_.get()); |
| 526 BrowserThread::PostTask( |
| 527 BrowserThread::FILE, FROM_HERE, |
| 528 // Will be deleted at end of task execution. |
| 529 base::Bind(&DownloadFile::Cancel, base::Owned(download_file_.release()))); |
| 530 |
| 531 // Cancel the originating URL request. |
| 532 request_handle_->CancelRequest(); |
| 533 |
485 download_stats::RecordDownloadInterrupted( | 534 download_stats::RecordDownloadInterrupted( |
486 reason, received_bytes_, total_bytes_); | 535 reason, received_bytes_, total_bytes_); |
487 delegate_->DownloadStopped(this); | 536 delegate_->DownloadStopped(this); |
488 } | 537 } |
489 | 538 |
490 void DownloadItemImpl::MarkAsComplete() { | 539 void DownloadItemImpl::MarkAsComplete() { |
491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
492 | 541 |
493 DCHECK(all_data_saved_); | 542 DCHECK(all_data_saved_); |
494 end_time_ = base::Time::Now(); | 543 end_time_ = base::Time::Now(); |
495 TransitionTo(COMPLETE); | 544 TransitionTo(COMPLETE); |
496 } | 545 } |
497 | 546 |
498 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { | 547 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { |
499 auto_opened_ = auto_opened; | 548 auto_opened_ = auto_opened; |
500 Completed(); | 549 Completed(); |
501 } | 550 } |
502 | 551 |
503 void DownloadItemImpl::OnAllDataSaved( | 552 void DownloadItemImpl::OnAllDataSaved( |
504 int64 size, const std::string& final_hash) { | 553 const std::string& final_hash) { |
505 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 554 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
506 | 555 |
| 556 DCHECK_EQ(IN_PROGRESS, state_); |
507 DCHECK(!all_data_saved_); | 557 DCHECK(!all_data_saved_); |
508 all_data_saved_ = true; | 558 all_data_saved_ = true; |
509 ProgressComplete(size, final_hash); | 559 |
| 560 // Store final hash and null out intermediate serialized hash state. |
| 561 hash_ = final_hash; |
| 562 hash_state_ = ""; |
| 563 |
510 UpdateObservers(); | 564 UpdateObservers(); |
511 } | 565 } |
512 | 566 |
513 void DownloadItemImpl::OnDownloadedFileRemoved() { | 567 void DownloadItemImpl::OnDownloadedFileRemoved() { |
514 file_externally_removed_ = true; | 568 file_externally_removed_ = true; |
515 UpdateObservers(); | 569 UpdateObservers(); |
516 } | 570 } |
517 | 571 |
518 void DownloadItemImpl::MaybeCompleteDownload() { | 572 void DownloadItemImpl::MaybeCompleteDownload() { |
519 // TODO(rdsmith): Move logic for this function here. | 573 // TODO(rdsmith): Move logic for this function here. |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
694 request_handle_->ResumeRequest(); | 748 request_handle_->ResumeRequest(); |
695 else | 749 else |
696 request_handle_->PauseRequest(); | 750 request_handle_->PauseRequest(); |
697 is_paused_ = !is_paused_; | 751 is_paused_ = !is_paused_; |
698 UpdateObservers(); | 752 UpdateObservers(); |
699 } | 753 } |
700 | 754 |
701 void DownloadItemImpl::OnDownloadCompleting() { | 755 void DownloadItemImpl::OnDownloadCompleting() { |
702 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 756 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
703 | 757 |
| 758 if (!IsInProgress()) |
| 759 return; |
| 760 |
704 VLOG(20) << __FUNCTION__ << "()" | 761 VLOG(20) << __FUNCTION__ << "()" |
705 << " needs rename = " << NeedsRename() | 762 << " needs rename = " << NeedsRename() |
706 << " " << DebugString(true); | 763 << " " << DebugString(true); |
707 DCHECK(!GetTargetName().empty()); | 764 DCHECK(!GetTargetName().empty()); |
708 DCHECK_NE(DANGEROUS, GetSafetyState()); | 765 DCHECK_NE(DANGEROUS, GetSafetyState()); |
709 | 766 |
| 767 DCHECK(download_file_.get()); |
710 if (NeedsRename()) { | 768 if (NeedsRename()) { |
711 DownloadFileManager::RenameCompletionCallback callback = | 769 content::DownloadFile::RenameCompletionCallback callback = |
712 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, | 770 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, |
713 weak_ptr_factory_.GetWeakPtr()); | 771 weak_ptr_factory_.GetWeakPtr()); |
714 BrowserThread::PostTask( | 772 BrowserThread::PostTask( |
715 BrowserThread::FILE, FROM_HERE, | 773 BrowserThread::FILE, FROM_HERE, |
716 base::Bind(&DownloadFileManager::RenameDownloadFile, | 774 base::Bind(&DownloadFile::Rename, |
717 delegate_->GetDownloadFileManager(), GetGlobalId(), | 775 base::Unretained(download_file_.get()), |
718 GetTargetFilePath(), true, callback)); | 776 GetTargetFilePath(), true, callback)); |
719 } else { | 777 } else { |
720 // Complete the download and release the DownloadFile. | 778 // Complete the download and release the DownloadFile. |
721 BrowserThread::PostTask( | 779 BrowserThread::PostTask( |
722 BrowserThread::FILE, FROM_HERE, | 780 BrowserThread::FILE, FROM_HERE, |
723 base::Bind(&DownloadFileManager::CompleteDownload, | 781 base::Bind(&ReleaseDownloadFile, base::Passed(download_file_.Pass()), |
724 delegate_->GetDownloadFileManager(), GetGlobalId(), | |
725 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | 782 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
726 weak_ptr_factory_.GetWeakPtr()))); | 783 weak_ptr_factory_.GetWeakPtr()))); |
727 } | 784 } |
728 } | 785 } |
729 | 786 |
730 void DownloadItemImpl::OnDownloadRenamedToFinalName( | 787 void DownloadItemImpl::OnDownloadRenamedToFinalName( |
731 content::DownloadInterruptReason reason, | 788 content::DownloadInterruptReason reason, |
732 const FilePath& full_path) { | 789 const FilePath& full_path) { |
733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 790 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
734 | 791 |
| 792 if (!IsInProgress()) |
| 793 return; |
| 794 |
735 VLOG(20) << __FUNCTION__ << "()" | 795 VLOG(20) << __FUNCTION__ << "()" |
736 << " full_path = \"" << full_path.value() << "\"" | 796 << " full_path = \"" << full_path.value() << "\"" |
737 << " needed rename = " << NeedsRename() | 797 << " needed rename = " << NeedsRename() |
738 << " " << DebugString(false); | 798 << " " << DebugString(false); |
739 DCHECK(NeedsRename()); | 799 DCHECK(NeedsRename()); |
740 | 800 |
741 if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 801 if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
742 Interrupt(reason); | 802 Interrupt(reason); |
743 return; | 803 return; |
744 } | 804 } |
745 | 805 |
746 // full_path is now the current and target file path. | 806 // full_path is now the current and target file path. |
747 DCHECK(!full_path.empty()); | 807 DCHECK(!full_path.empty()); |
748 target_path_ = full_path; | 808 target_path_ = full_path; |
749 SetFullPath(full_path); | 809 SetFullPath(full_path); |
750 delegate_->DownloadRenamedToFinalName(this); | 810 delegate_->DownloadRenamedToFinalName(this); |
751 | 811 |
752 // Complete the download and release the DownloadFile. | 812 // Complete the download and release the DownloadFile. |
| 813 // TODO(rdsmith): Unify this path with the !NeedsRename() path in |
| 814 // OnDownloadCompleting above. This can happen easily after history |
| 815 // is made into an observer and the path accessors are cleaned up; |
| 816 // that should allow OnDownloadCompleting to simply call |
| 817 // OnDownloadRenamedToFinalName directly. |
| 818 DCHECK(download_file_.get()); |
753 BrowserThread::PostTask( | 819 BrowserThread::PostTask( |
754 BrowserThread::FILE, FROM_HERE, | 820 BrowserThread::FILE, FROM_HERE, |
755 base::Bind(&DownloadFileManager::CompleteDownload, | 821 base::Bind(&ReleaseDownloadFile, base::Passed(download_file_.Pass()), |
756 delegate_->GetDownloadFileManager(), GetGlobalId(), | |
757 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | 822 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
758 weak_ptr_factory_.GetWeakPtr()))); | 823 weak_ptr_factory_.GetWeakPtr()))); |
759 } | 824 } |
760 | 825 |
| 826 void DownloadItemImpl::OnDownloadFileInitialized( |
| 827 content::DownloadInterruptReason result) { |
| 828 if (result != content::DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 829 Interrupt(result); |
| 830 // TODO(rdsmith): It makes no sense to continue along the |
| 831 // regular download path after we've gotten an error. But it's |
| 832 // the way the code has historically worked, and this allows us |
| 833 // to get the download persisted and observers of the download manager |
| 834 // notified, so tests work. When we execute all side effects of cancel |
| 835 // (including queue removal) immedately rather than waiting for |
| 836 // persistence we should replace this comment with a "return;". |
| 837 } |
| 838 |
| 839 delegate_->DelegateStart(this); |
| 840 } |
| 841 |
761 void DownloadItemImpl::OnDownloadFileReleased() { | 842 void DownloadItemImpl::OnDownloadFileReleased() { |
762 if (delegate_->ShouldOpenDownload(this)) | 843 if (delegate_->ShouldOpenDownload(this)) |
763 Completed(); | 844 Completed(); |
764 else | 845 else |
765 delegate_delayed_complete_ = true; | 846 delegate_delayed_complete_ = true; |
766 } | 847 } |
767 | 848 |
768 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( | 849 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( |
769 content::DownloadInterruptReason reason, | 850 content::DownloadInterruptReason reason, |
770 const FilePath& full_path) { | 851 const FilePath& full_path) { |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
879 target_path_ = target_path; | 960 target_path_ = target_path; |
880 target_disposition_ = disposition; | 961 target_disposition_ = disposition; |
881 SetDangerType(danger_type); | 962 SetDangerType(danger_type); |
882 // TODO(asanka): SetDangerType() doesn't need to send a notification here. | 963 // TODO(asanka): SetDangerType() doesn't need to send a notification here. |
883 | 964 |
884 // We want the intermediate and target paths to refer to the same directory so | 965 // We want the intermediate and target paths to refer to the same directory so |
885 // that they are both on the same device and subject to same | 966 // that they are both on the same device and subject to same |
886 // space/permission/availability constraints. | 967 // space/permission/availability constraints. |
887 DCHECK(intermediate_path.DirName() == target_path.DirName()); | 968 DCHECK(intermediate_path.DirName() == target_path.DirName()); |
888 | 969 |
| 970 if (!IsInProgress()) { |
| 971 // If we've been cancelled or interrupted while the target was being |
| 972 // determined, continue the cascade with a null name. |
| 973 // The error doesn't matter as the cause of download stoppaged |
| 974 // will already have been recorded. |
| 975 OnDownloadRenamedToIntermediateName( |
| 976 content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, FilePath()); |
| 977 return; |
| 978 } |
| 979 |
889 // Rename to intermediate name. | 980 // Rename to intermediate name. |
890 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a | 981 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a |
891 // spurious rename when we can just rename to the final | 982 // spurious rename when we can just rename to the final |
892 // filename. Unnecessary renames may cause bugs like | 983 // filename. Unnecessary renames may cause bugs like |
893 // http://crbug.com/74187. | 984 // http://crbug.com/74187. |
894 DownloadFileManager::RenameCompletionCallback callback = | 985 DCHECK(download_file_.get()); |
| 986 DownloadFile::RenameCompletionCallback callback = |
895 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, | 987 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, |
896 weak_ptr_factory_.GetWeakPtr()); | 988 weak_ptr_factory_.GetWeakPtr()); |
897 BrowserThread::PostTask( | 989 BrowserThread::PostTask( |
898 BrowserThread::FILE, FROM_HERE, | 990 BrowserThread::FILE, FROM_HERE, |
899 base::Bind(&DownloadFileManager::RenameDownloadFile, | 991 base::Bind(&DownloadFile::Rename, |
900 delegate_->GetDownloadFileManager(), GetGlobalId(), | 992 // Safe because we control download file lifetime. |
| 993 base::Unretained(download_file_.get()), |
901 intermediate_path, false, callback)); | 994 intermediate_path, false, callback)); |
902 } | 995 } |
903 | 996 |
904 void DownloadItemImpl::OnContentCheckCompleted( | 997 void DownloadItemImpl::OnContentCheckCompleted( |
905 content::DownloadDangerType danger_type) { | 998 content::DownloadDangerType danger_type) { |
906 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 999 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
907 DCHECK(AllDataSaved()); | 1000 DCHECK(AllDataSaved()); |
908 SetDangerType(danger_type); | 1001 SetDangerType(danger_type); |
909 UpdateObservers(); | 1002 UpdateObservers(); |
910 } | 1003 } |
(...skipping 10 matching lines...) Expand all Loading... |
921 | 1014 |
922 void DownloadItemImpl::SetDisplayName(const FilePath& name) { | 1015 void DownloadItemImpl::SetDisplayName(const FilePath& name) { |
923 display_name_ = name; | 1016 display_name_ = name; |
924 } | 1017 } |
925 | 1018 |
926 FilePath DownloadItemImpl::GetUserVerifiedFilePath() const { | 1019 FilePath DownloadItemImpl::GetUserVerifiedFilePath() const { |
927 return (safety_state_ == DownloadItem::SAFE) ? | 1020 return (safety_state_ == DownloadItem::SAFE) ? |
928 GetTargetFilePath() : GetFullPath(); | 1021 GetTargetFilePath() : GetFullPath(); |
929 } | 1022 } |
930 | 1023 |
931 void DownloadItemImpl::OffThreadCancel() { | 1024 void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far, |
| 1025 int64 bytes_per_sec, |
| 1026 const std::string& hash_state) { |
932 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1027 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
933 request_handle_->CancelRequest(); | |
934 | 1028 |
935 BrowserThread::PostTask( | 1029 if (!IsInProgress()) { |
936 BrowserThread::FILE, FROM_HERE, | 1030 // Ignore if we're no longer in-progress. This can happen if we race a |
937 base::Bind(&DownloadFileManager::CancelDownload, | 1031 // Cancel on the UI thread with an update on the FILE thread. |
938 delegate_->GetDownloadFileManager(), download_id_)); | 1032 // |
| 1033 // TODO(rdsmith): Arguably we should let this go through, as this means |
| 1034 // the download really did get further than we know before it was |
| 1035 // cancelled. But the gain isn't very large, and the code is more |
| 1036 // fragile if it has to support in progress updates in a non-in-progress |
| 1037 // state. This issue should be readdressed when we revamp performance |
| 1038 // reporting. |
| 1039 return; |
| 1040 } |
| 1041 bytes_per_sec_ = bytes_per_sec; |
| 1042 hash_state_ = hash_state; |
| 1043 received_bytes_ = bytes_so_far; |
| 1044 |
| 1045 // If we've received more data than we were expecting (bad server info?), |
| 1046 // revert to 'unknown size mode'. |
| 1047 if (received_bytes_ > total_bytes_) |
| 1048 total_bytes_ = 0; |
| 1049 |
| 1050 if (bound_net_log_.IsLoggingAllEvents()) { |
| 1051 bound_net_log_.AddEvent( |
| 1052 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED, |
| 1053 net::NetLog::Int64Callback("bytes_so_far", received_bytes_)); |
| 1054 } |
| 1055 |
| 1056 UpdateObservers(); |
| 1057 } |
| 1058 |
| 1059 void DownloadItemImpl::DestinationError( |
| 1060 content::DownloadInterruptReason reason) { |
| 1061 // The DestinationError and Interrupt routines are being kept separate |
| 1062 // to allow for a future merging of the Cancel and Interrupt routines.. |
| 1063 Interrupt(reason); |
| 1064 } |
| 1065 |
| 1066 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { |
| 1067 if (!IsInProgress()) |
| 1068 return; |
| 1069 OnAllDataSaved(final_hash); |
| 1070 delegate_->MaybeCompleteDownload(this); |
939 } | 1071 } |
940 | 1072 |
941 void DownloadItemImpl::Init(bool active, | 1073 void DownloadItemImpl::Init(bool active, |
942 download_net_logs::DownloadType download_type) { | 1074 download_net_logs::DownloadType download_type) { |
943 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1075 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
944 | 1076 |
945 if (active) | 1077 if (active) |
946 download_stats::RecordDownloadCount(download_stats::START_COUNT); | 1078 download_stats::RecordDownloadCount(download_stats::START_COUNT); |
947 | 1079 |
948 if (target_path_.empty()) | 1080 if (target_path_.empty()) |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1039 " total = %" PRId64 | 1171 " total = %" PRId64 |
1040 " received = %" PRId64 | 1172 " received = %" PRId64 |
1041 " reason = %s" | 1173 " reason = %s" |
1042 " paused = %c" | 1174 " paused = %c" |
1043 " otr = %c" | 1175 " otr = %c" |
1044 " safety = %s" | 1176 " safety = %s" |
1045 " last_modified = '%s'" | 1177 " last_modified = '%s'" |
1046 " etag = '%s'" | 1178 " etag = '%s'" |
1047 " url_chain = \n\t\"%s\"\n\t" | 1179 " url_chain = \n\t\"%s\"\n\t" |
1048 " full_path = \"%" PRFilePath "\"" | 1180 " full_path = \"%" PRFilePath "\"" |
1049 " target_path = \"%" PRFilePath "\"", | 1181 " target_path = \"%" PRFilePath "\"" |
| 1182 " has download file = %s", |
1050 GetDbHandle(), | 1183 GetDbHandle(), |
1051 GetTotalBytes(), | 1184 GetTotalBytes(), |
1052 GetReceivedBytes(), | 1185 GetReceivedBytes(), |
1053 InterruptReasonDebugString(last_reason_).c_str(), | 1186 InterruptReasonDebugString(last_reason_).c_str(), |
1054 IsPaused() ? 'T' : 'F', | 1187 IsPaused() ? 'T' : 'F', |
1055 IsOtr() ? 'T' : 'F', | 1188 IsOtr() ? 'T' : 'F', |
1056 DebugSafetyStateString(GetSafetyState()), | 1189 DebugSafetyStateString(GetSafetyState()), |
1057 GetLastModifiedTime().c_str(), | 1190 GetLastModifiedTime().c_str(), |
1058 GetETag().c_str(), | 1191 GetETag().c_str(), |
1059 url_list.c_str(), | 1192 url_list.c_str(), |
1060 GetFullPath().value().c_str(), | 1193 GetFullPath().value().c_str(), |
1061 GetTargetFilePath().value().c_str()); | 1194 GetTargetFilePath().value().c_str(), |
| 1195 download_file_.get() ? "true" : "false"); |
1062 } else { | 1196 } else { |
1063 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); | 1197 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); |
1064 } | 1198 } |
1065 | 1199 |
1066 description += " }"; | 1200 description += " }"; |
1067 | 1201 |
1068 return description; | 1202 return description; |
1069 } | 1203 } |
1070 | 1204 |
1071 bool DownloadItemImpl::AllDataSaved() const { return all_data_saved_; } | 1205 bool DownloadItemImpl::AllDataSaved() const { return all_data_saved_; } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1162 void DownloadItemImpl::SetOpened(bool opened) { opened_ = opened; } | 1296 void DownloadItemImpl::SetOpened(bool opened) { opened_ = opened; } |
1163 bool DownloadItemImpl::GetOpened() const { return opened_; } | 1297 bool DownloadItemImpl::GetOpened() const { return opened_; } |
1164 const std::string& DownloadItemImpl::GetLastModifiedTime() const { | 1298 const std::string& DownloadItemImpl::GetLastModifiedTime() const { |
1165 return last_modified_time_; | 1299 return last_modified_time_; |
1166 } | 1300 } |
1167 const std::string& DownloadItemImpl::GetETag() const { return etag_; } | 1301 const std::string& DownloadItemImpl::GetETag() const { return etag_; } |
1168 content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const { | 1302 content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const { |
1169 return last_reason_; | 1303 return last_reason_; |
1170 } | 1304 } |
1171 void DownloadItemImpl::MockDownloadOpenForTesting() { open_enabled_ = false; } | 1305 void DownloadItemImpl::MockDownloadOpenForTesting() { open_enabled_ = false; } |
OLD | NEW |