| 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 STLDeleteContainerPairSecondPointers( | 323 STLDeleteContainerPairSecondPointers( |
| 302 external_data_map_.begin(), external_data_map_.end()); | 324 external_data_map_.begin(), external_data_map_.end()); |
| 303 delegate_->AssertStateConsistent(this); | 325 delegate_->AssertStateConsistent(this); |
| 304 delegate_->Detach(); | 326 delegate_->Detach(); |
| 305 } | 327 } |
| 306 | 328 |
| 329 base::WeakPtr<content::DownloadDestinationObserver> |
| 330 DownloadItemImpl::DestinationObserverAsWeakPtr() { |
| 331 // Return does private downcast. |
| 332 return weak_ptr_factory_.GetWeakPtr(); |
| 333 } |
| 334 |
| 307 void DownloadItemImpl::AddObserver(Observer* observer) { | 335 void DownloadItemImpl::AddObserver(Observer* observer) { |
| 308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 309 | 337 |
| 310 observers_.AddObserver(observer); | 338 observers_.AddObserver(observer); |
| 311 } | 339 } |
| 312 | 340 |
| 313 void DownloadItemImpl::RemoveObserver(Observer* observer) { | 341 void DownloadItemImpl::RemoveObserver(Observer* observer) { |
| 314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 315 | 343 |
| 316 observers_.RemoveObserver(observer); | 344 observers_.RemoveObserver(observer); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 bound_net_log_.AddEvent( | 413 bound_net_log_.AddEvent( |
| 386 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, | 414 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, |
| 387 base::Bind(&download_net_logs::ItemCheckedCallback, | 415 base::Bind(&download_net_logs::ItemCheckedCallback, |
| 388 GetDangerType(), GetSafetyState())); | 416 GetDangerType(), GetSafetyState())); |
| 389 | 417 |
| 390 UpdateObservers(); | 418 UpdateObservers(); |
| 391 | 419 |
| 392 delegate_->MaybeCompleteDownload(this); | 420 delegate_->MaybeCompleteDownload(this); |
| 393 } | 421 } |
| 394 | 422 |
| 395 void DownloadItemImpl::ProgressComplete(int64 bytes_so_far, | |
| 396 const std::string& final_hash) { | |
| 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 398 | |
| 399 hash_ = final_hash; | |
| 400 hash_state_ = ""; | |
| 401 | |
| 402 received_bytes_ = bytes_so_far; | |
| 403 | |
| 404 // If we've received more data than we were expecting (bad server info?), | |
| 405 // revert to 'unknown size mode'. | |
| 406 if (received_bytes_ > total_bytes_) | |
| 407 total_bytes_ = 0; | |
| 408 } | |
| 409 | |
| 410 // Updates from the download thread may have been posted while this download | 423 // Updates from the download thread may have been posted while this download |
| 411 // was being cancelled in the UI thread, so we'll accept them unless we're | 424 // was being cancelled in the UI thread, so we'll accept them unless we're |
| 412 // complete. | 425 // complete. |
| 413 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, | 426 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, |
| 414 int64 bytes_per_sec, | 427 int64 bytes_per_sec, |
| 415 const std::string& hash_state) { | 428 const std::string& hash_state) { |
| 416 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 417 | 430 |
| 418 if (!IsInProgress()) { | 431 if (!IsInProgress()) { |
| 419 // Ignore if we're no longer in-progress. This can happen if we race a | 432 // 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... |
| 456 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); | 469 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
| 457 if (!IsPartialDownload()) { | 470 if (!IsPartialDownload()) { |
| 458 // Small downloads might be complete before this method has | 471 // Small downloads might be complete before this method has |
| 459 // a chance to run. | 472 // a chance to run. |
| 460 return; | 473 return; |
| 461 } | 474 } |
| 462 | 475 |
| 463 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); | 476 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); |
| 464 | 477 |
| 465 TransitionTo(CANCELLED); | 478 TransitionTo(CANCELLED); |
| 479 |
| 480 // Cancel and remove the download file. |
| 481 DCHECK(download_file_.get()); |
| 482 BrowserThread::PostTask( |
| 483 BrowserThread::FILE, FROM_HERE, |
| 484 // Will be deleted at end of task execution. |
| 485 base::Bind(&DownloadFile::Cancel, base::Owned(download_file_.release()))); |
| 486 |
| 487 // Cancel the originating URL request. |
| 488 request_handle_->CancelRequest(); |
| 489 |
| 466 if (user_cancel) | 490 if (user_cancel) |
| 467 delegate_->DownloadStopped(this); | 491 delegate_->DownloadStopped(this); |
| 468 } | 492 } |
| 469 | 493 |
| 494 // We're starting the download. |
| 495 void DownloadItemImpl::Start(scoped_ptr<content::DownloadFile> download_file) { |
| 496 DCHECK(!download_file_.get()); |
| 497 download_file_ = download_file.Pass(); |
| 498 |
| 499 BrowserThread::PostTask( |
| 500 BrowserThread::FILE, FROM_HERE, |
| 501 base::Bind(&DownloadFile::Initialize, |
| 502 // Safe because we control download file lifetime. |
| 503 base::Unretained(download_file_.get()), |
| 504 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, |
| 505 weak_ptr_factory_.GetWeakPtr()))); |
| 506 } |
| 507 |
| 470 // An error occurred somewhere. | 508 // An error occurred somewhere. |
| 471 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { | 509 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { |
| 472 // Somewhat counter-intuitively, it is possible for us to receive an | 510 // Somewhat counter-intuitively, it is possible for us to receive an |
| 473 // interrupt after we've already been interrupted. The generation of | 511 // interrupt after we've already been interrupted. The generation of |
| 474 // interrupts from the file thread Renames and the generation of | 512 // interrupts from the file thread Renames and the generation of |
| 475 // interrupts from disk writes go through two different mechanisms (driven | 513 // interrupts from disk writes go through two different mechanisms (driven |
| 476 // by rename requests from UI thread and by write requests from IO thread, | 514 // by rename requests from UI thread and by write requests from IO thread, |
| 477 // respectively), and since we choose not to keep state on the File thread, | 515 // respectively), and since we choose not to keep state on the File thread, |
| 478 // this is the place where the races collide. It's also possible for | 516 // this is the place where the races collide. It's also possible for |
| 479 // interrupts to race with cancels. | 517 // interrupts to race with cancels. |
| 480 | 518 |
| 481 // Whatever happens, the first one to hit the UI thread wins. | 519 // Whatever happens, the first one to hit the UI thread wins. |
| 482 if (!IsInProgress()) | 520 if (!IsInProgress()) |
| 483 return; | 521 return; |
| 484 | 522 |
| 485 last_reason_ = reason; | 523 last_reason_ = reason; |
| 486 TransitionTo(INTERRUPTED); | 524 TransitionTo(INTERRUPTED); |
| 525 |
| 526 // Cancel and remove the download file. |
| 527 DCHECK(download_file_.get()); |
| 528 BrowserThread::PostTask( |
| 529 BrowserThread::FILE, FROM_HERE, |
| 530 // Will be deleted at end of task execution. |
| 531 base::Bind(&DownloadFile::Cancel, base::Owned(download_file_.release()))); |
| 532 |
| 533 // Cancel the originating URL request. |
| 534 request_handle_->CancelRequest(); |
| 535 |
| 487 download_stats::RecordDownloadInterrupted( | 536 download_stats::RecordDownloadInterrupted( |
| 488 reason, received_bytes_, total_bytes_); | 537 reason, received_bytes_, total_bytes_); |
| 489 delegate_->DownloadStopped(this); | 538 delegate_->DownloadStopped(this); |
| 490 } | 539 } |
| 491 | 540 |
| 492 void DownloadItemImpl::MarkAsComplete() { | 541 void DownloadItemImpl::MarkAsComplete() { |
| 493 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 542 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 494 | 543 |
| 495 DCHECK(all_data_saved_); | 544 DCHECK(all_data_saved_); |
| 496 end_time_ = base::Time::Now(); | 545 end_time_ = base::Time::Now(); |
| 497 TransitionTo(COMPLETE); | 546 TransitionTo(COMPLETE); |
| 498 } | 547 } |
| 499 | 548 |
| 500 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { | 549 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { |
| 501 auto_opened_ = auto_opened; | 550 auto_opened_ = auto_opened; |
| 502 Completed(); | 551 Completed(); |
| 503 } | 552 } |
| 504 | 553 |
| 505 void DownloadItemImpl::OnAllDataSaved( | 554 void DownloadItemImpl::OnAllDataSaved( |
| 506 int64 size, const std::string& final_hash) { | 555 const std::string& final_hash) { |
| 507 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 556 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 508 | 557 |
| 558 DCHECK_EQ(IN_PROGRESS, state_); |
| 509 DCHECK(!all_data_saved_); | 559 DCHECK(!all_data_saved_); |
| 510 all_data_saved_ = true; | 560 all_data_saved_ = true; |
| 511 ProgressComplete(size, final_hash); | 561 |
| 562 // Store final hash and null out intermediate serialized hash state. |
| 563 hash_ = final_hash; |
| 564 hash_state_ = ""; |
| 565 |
| 512 UpdateObservers(); | 566 UpdateObservers(); |
| 513 } | 567 } |
| 514 | 568 |
| 515 void DownloadItemImpl::OnDownloadedFileRemoved() { | 569 void DownloadItemImpl::OnDownloadedFileRemoved() { |
| 516 file_externally_removed_ = true; | 570 file_externally_removed_ = true; |
| 517 UpdateObservers(); | 571 UpdateObservers(); |
| 518 } | 572 } |
| 519 | 573 |
| 520 void DownloadItemImpl::MaybeCompleteDownload() { | 574 void DownloadItemImpl::MaybeCompleteDownload() { |
| 521 // TODO(rdsmith): Move logic for this function here. | 575 // TODO(rdsmith): Move logic for this function here. |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 696 request_handle_->ResumeRequest(); | 750 request_handle_->ResumeRequest(); |
| 697 else | 751 else |
| 698 request_handle_->PauseRequest(); | 752 request_handle_->PauseRequest(); |
| 699 is_paused_ = !is_paused_; | 753 is_paused_ = !is_paused_; |
| 700 UpdateObservers(); | 754 UpdateObservers(); |
| 701 } | 755 } |
| 702 | 756 |
| 703 void DownloadItemImpl::OnDownloadCompleting() { | 757 void DownloadItemImpl::OnDownloadCompleting() { |
| 704 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 758 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 705 | 759 |
| 760 if (!IsInProgress()) |
| 761 return; |
| 762 |
| 706 VLOG(20) << __FUNCTION__ << "()" | 763 VLOG(20) << __FUNCTION__ << "()" |
| 707 << " needs rename = " << NeedsRename() | 764 << " needs rename = " << NeedsRename() |
| 708 << " " << DebugString(true); | 765 << " " << DebugString(true); |
| 709 DCHECK(!GetTargetName().empty()); | 766 DCHECK(!GetTargetName().empty()); |
| 710 DCHECK_NE(DANGEROUS, GetSafetyState()); | 767 DCHECK_NE(DANGEROUS, GetSafetyState()); |
| 711 | 768 |
| 769 DCHECK(download_file_.get()); |
| 712 if (NeedsRename()) { | 770 if (NeedsRename()) { |
| 713 DownloadFileManager::RenameCompletionCallback callback = | 771 content::DownloadFile::RenameCompletionCallback callback = |
| 714 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, | 772 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, |
| 715 weak_ptr_factory_.GetWeakPtr()); | 773 weak_ptr_factory_.GetWeakPtr()); |
| 716 BrowserThread::PostTask( | 774 BrowserThread::PostTask( |
| 717 BrowserThread::FILE, FROM_HERE, | 775 BrowserThread::FILE, FROM_HERE, |
| 718 base::Bind(&DownloadFileManager::RenameDownloadFile, | 776 base::Bind(&DownloadFile::Rename, |
| 719 delegate_->GetDownloadFileManager(), GetGlobalId(), | 777 base::Unretained(download_file_.get()), |
| 720 GetTargetFilePath(), true, callback)); | 778 GetTargetFilePath(), true, callback)); |
| 721 } else { | 779 } else { |
| 722 // Complete the download and release the DownloadFile. | 780 // Complete the download and release the DownloadFile. |
| 723 BrowserThread::PostTask( | 781 BrowserThread::PostTask( |
| 724 BrowserThread::FILE, FROM_HERE, | 782 BrowserThread::FILE, FROM_HERE, |
| 725 base::Bind(&DownloadFileManager::CompleteDownload, | 783 base::Bind(&ReleaseDownloadFile, base::Passed(download_file_.Pass()), |
| 726 delegate_->GetDownloadFileManager(), GetGlobalId(), | |
| 727 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | 784 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
| 728 weak_ptr_factory_.GetWeakPtr()))); | 785 weak_ptr_factory_.GetWeakPtr()))); |
| 729 } | 786 } |
| 730 } | 787 } |
| 731 | 788 |
| 732 void DownloadItemImpl::OnDownloadRenamedToFinalName( | 789 void DownloadItemImpl::OnDownloadRenamedToFinalName( |
| 733 content::DownloadInterruptReason reason, | 790 content::DownloadInterruptReason reason, |
| 734 const FilePath& full_path) { | 791 const FilePath& full_path) { |
| 735 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 792 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 736 | 793 |
| 794 if (!IsInProgress()) |
| 795 return; |
| 796 |
| 737 VLOG(20) << __FUNCTION__ << "()" | 797 VLOG(20) << __FUNCTION__ << "()" |
| 738 << " full_path = \"" << full_path.value() << "\"" | 798 << " full_path = \"" << full_path.value() << "\"" |
| 739 << " needed rename = " << NeedsRename() | 799 << " needed rename = " << NeedsRename() |
| 740 << " " << DebugString(false); | 800 << " " << DebugString(false); |
| 741 DCHECK(NeedsRename()); | 801 DCHECK(NeedsRename()); |
| 742 | 802 |
| 743 if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 803 if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
| 744 Interrupt(reason); | 804 Interrupt(reason); |
| 745 return; | 805 return; |
| 746 } | 806 } |
| 747 | 807 |
| 748 // full_path is now the current and target file path. | 808 // full_path is now the current and target file path. |
| 749 DCHECK(!full_path.empty()); | 809 DCHECK(!full_path.empty()); |
| 750 target_path_ = full_path; | 810 target_path_ = full_path; |
| 751 SetFullPath(full_path); | 811 SetFullPath(full_path); |
| 752 delegate_->DownloadRenamedToFinalName(this); | 812 delegate_->DownloadRenamedToFinalName(this); |
| 753 | 813 |
| 754 // Complete the download and release the DownloadFile. | 814 // Complete the download and release the DownloadFile. |
| 815 // TODO(rdsmith): Unify this path with the !NeedsRename() path in |
| 816 // OnDownloadCompleting above. This can happen easily after history |
| 817 // is made into an observer and the path accessors are cleaned up; |
| 818 // that should allow OnDownloadCompleting to simply call |
| 819 // OnDownloadRenamedToFinalName directly. |
| 820 DCHECK(download_file_.get()); |
| 755 BrowserThread::PostTask( | 821 BrowserThread::PostTask( |
| 756 BrowserThread::FILE, FROM_HERE, | 822 BrowserThread::FILE, FROM_HERE, |
| 757 base::Bind(&DownloadFileManager::CompleteDownload, | 823 base::Bind(&ReleaseDownloadFile, base::Passed(download_file_.Pass()), |
| 758 delegate_->GetDownloadFileManager(), GetGlobalId(), | |
| 759 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | 824 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
| 760 weak_ptr_factory_.GetWeakPtr()))); | 825 weak_ptr_factory_.GetWeakPtr()))); |
| 761 } | 826 } |
| 762 | 827 |
| 828 void DownloadItemImpl::OnDownloadFileInitialized( |
| 829 content::DownloadInterruptReason result) { |
| 830 if (result != content::DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 831 Interrupt(result); |
| 832 // TODO(rdsmith): It makes no sense to continue along the |
| 833 // regular download path after we've gotten an error. But it's |
| 834 // the way the code has historically worked, and this allows us |
| 835 // to get the download persisted and observers of the download manager |
| 836 // notified, so tests work. When we execute all side effects of cancel |
| 837 // (including queue removal) immedately rather than waiting for |
| 838 // persistence we should replace this comment with a "return;". |
| 839 } |
| 840 |
| 841 delegate_->DelegateStart(this); |
| 842 } |
| 843 |
| 763 void DownloadItemImpl::OnDownloadFileReleased() { | 844 void DownloadItemImpl::OnDownloadFileReleased() { |
| 764 if (delegate_->ShouldOpenDownload(this)) | 845 if (delegate_->ShouldOpenDownload(this)) |
| 765 Completed(); | 846 Completed(); |
| 766 else | 847 else |
| 767 delegate_delayed_complete_ = true; | 848 delegate_delayed_complete_ = true; |
| 768 } | 849 } |
| 769 | 850 |
| 770 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( | 851 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( |
| 771 content::DownloadInterruptReason reason, | 852 content::DownloadInterruptReason reason, |
| 772 const FilePath& full_path) { | 853 const FilePath& full_path) { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 target_path_ = target_path; | 962 target_path_ = target_path; |
| 882 target_disposition_ = disposition; | 963 target_disposition_ = disposition; |
| 883 SetDangerType(danger_type); | 964 SetDangerType(danger_type); |
| 884 // TODO(asanka): SetDangerType() doesn't need to send a notification here. | 965 // TODO(asanka): SetDangerType() doesn't need to send a notification here. |
| 885 | 966 |
| 886 // We want the intermediate and target paths to refer to the same directory so | 967 // We want the intermediate and target paths to refer to the same directory so |
| 887 // that they are both on the same device and subject to same | 968 // that they are both on the same device and subject to same |
| 888 // space/permission/availability constraints. | 969 // space/permission/availability constraints. |
| 889 DCHECK(intermediate_path.DirName() == target_path.DirName()); | 970 DCHECK(intermediate_path.DirName() == target_path.DirName()); |
| 890 | 971 |
| 972 if (!IsInProgress()) { |
| 973 // If we've been cancelled or interrupted while the target was being |
| 974 // determined, continue the cascade with a null name. |
| 975 // The error doesn't matter as the cause of download stoppaged |
| 976 // will already have been recorded. |
| 977 OnDownloadRenamedToIntermediateName( |
| 978 content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, FilePath()); |
| 979 return; |
| 980 } |
| 981 |
| 891 // Rename to intermediate name. | 982 // Rename to intermediate name. |
| 892 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a | 983 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a |
| 893 // spurious rename when we can just rename to the final | 984 // spurious rename when we can just rename to the final |
| 894 // filename. Unnecessary renames may cause bugs like | 985 // filename. Unnecessary renames may cause bugs like |
| 895 // http://crbug.com/74187. | 986 // http://crbug.com/74187. |
| 896 DownloadFileManager::RenameCompletionCallback callback = | 987 DCHECK(download_file_.get()); |
| 988 DownloadFile::RenameCompletionCallback callback = |
| 897 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, | 989 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, |
| 898 weak_ptr_factory_.GetWeakPtr()); | 990 weak_ptr_factory_.GetWeakPtr()); |
| 899 BrowserThread::PostTask( | 991 BrowserThread::PostTask( |
| 900 BrowserThread::FILE, FROM_HERE, | 992 BrowserThread::FILE, FROM_HERE, |
| 901 base::Bind(&DownloadFileManager::RenameDownloadFile, | 993 base::Bind(&DownloadFile::Rename, |
| 902 delegate_->GetDownloadFileManager(), GetGlobalId(), | 994 // Safe because we control download file lifetime. |
| 995 base::Unretained(download_file_.get()), |
| 903 intermediate_path, false, callback)); | 996 intermediate_path, false, callback)); |
| 904 } | 997 } |
| 905 | 998 |
| 906 void DownloadItemImpl::OnContentCheckCompleted( | 999 void DownloadItemImpl::OnContentCheckCompleted( |
| 907 content::DownloadDangerType danger_type) { | 1000 content::DownloadDangerType danger_type) { |
| 908 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1001 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 909 DCHECK(AllDataSaved()); | 1002 DCHECK(AllDataSaved()); |
| 910 SetDangerType(danger_type); | 1003 SetDangerType(danger_type); |
| 911 UpdateObservers(); | 1004 UpdateObservers(); |
| 912 } | 1005 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 923 | 1016 |
| 924 void DownloadItemImpl::SetDisplayName(const FilePath& name) { | 1017 void DownloadItemImpl::SetDisplayName(const FilePath& name) { |
| 925 display_name_ = name; | 1018 display_name_ = name; |
| 926 } | 1019 } |
| 927 | 1020 |
| 928 FilePath DownloadItemImpl::GetUserVerifiedFilePath() const { | 1021 FilePath DownloadItemImpl::GetUserVerifiedFilePath() const { |
| 929 return (safety_state_ == DownloadItem::SAFE) ? | 1022 return (safety_state_ == DownloadItem::SAFE) ? |
| 930 GetTargetFilePath() : GetFullPath(); | 1023 GetTargetFilePath() : GetFullPath(); |
| 931 } | 1024 } |
| 932 | 1025 |
| 933 void DownloadItemImpl::OffThreadCancel() { | 1026 void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far, |
| 1027 int64 bytes_per_sec, |
| 1028 const std::string& hash_state) { |
| 934 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1029 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 935 request_handle_->CancelRequest(); | |
| 936 | 1030 |
| 937 BrowserThread::PostTask( | 1031 if (!IsInProgress()) { |
| 938 BrowserThread::FILE, FROM_HERE, | 1032 // Ignore if we're no longer in-progress. This can happen if we race a |
| 939 base::Bind(&DownloadFileManager::CancelDownload, | 1033 // Cancel on the UI thread with an update on the FILE thread. |
| 940 delegate_->GetDownloadFileManager(), download_id_)); | 1034 // |
| 1035 // TODO(rdsmith): Arguably we should let this go through, as this means |
| 1036 // the download really did get further than we know before it was |
| 1037 // cancelled. But the gain isn't very large, and the code is more |
| 1038 // fragile if it has to support in progress updates in a non-in-progress |
| 1039 // state. This issue should be readdressed when we revamp performance |
| 1040 // reporting. |
| 1041 return; |
| 1042 } |
| 1043 bytes_per_sec_ = bytes_per_sec; |
| 1044 hash_state_ = hash_state; |
| 1045 received_bytes_ = bytes_so_far; |
| 1046 |
| 1047 // If we've received more data than we were expecting (bad server info?), |
| 1048 // revert to 'unknown size mode'. |
| 1049 if (received_bytes_ > total_bytes_) |
| 1050 total_bytes_ = 0; |
| 1051 |
| 1052 if (bound_net_log_.IsLoggingAllEvents()) { |
| 1053 bound_net_log_.AddEvent( |
| 1054 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED, |
| 1055 net::NetLog::Int64Callback("bytes_so_far", received_bytes_)); |
| 1056 } |
| 1057 |
| 1058 UpdateObservers(); |
| 1059 } |
| 1060 |
| 1061 void DownloadItemImpl::DestinationError( |
| 1062 content::DownloadInterruptReason reason) { |
| 1063 // The DestinationError and Interrupt routines are being kept separate |
| 1064 // to allow for a future merging of the Cancel and Interrupt routines.. |
| 1065 Interrupt(reason); |
| 1066 } |
| 1067 |
| 1068 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { |
| 1069 if (!IsInProgress()) |
| 1070 return; |
| 1071 OnAllDataSaved(final_hash); |
| 1072 delegate_->MaybeCompleteDownload(this); |
| 941 } | 1073 } |
| 942 | 1074 |
| 943 void DownloadItemImpl::Init(bool active, | 1075 void DownloadItemImpl::Init(bool active, |
| 944 download_net_logs::DownloadType download_type) { | 1076 download_net_logs::DownloadType download_type) { |
| 945 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1077 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 946 | 1078 |
| 947 if (active) | 1079 if (active) |
| 948 download_stats::RecordDownloadCount(download_stats::START_COUNT); | 1080 download_stats::RecordDownloadCount(download_stats::START_COUNT); |
| 949 | 1081 |
| 950 if (target_path_.empty()) | 1082 if (target_path_.empty()) |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1041 " total = %" PRId64 | 1173 " total = %" PRId64 |
| 1042 " received = %" PRId64 | 1174 " received = %" PRId64 |
| 1043 " reason = %s" | 1175 " reason = %s" |
| 1044 " paused = %c" | 1176 " paused = %c" |
| 1045 " otr = %c" | 1177 " otr = %c" |
| 1046 " safety = %s" | 1178 " safety = %s" |
| 1047 " last_modified = '%s'" | 1179 " last_modified = '%s'" |
| 1048 " etag = '%s'" | 1180 " etag = '%s'" |
| 1049 " url_chain = \n\t\"%s\"\n\t" | 1181 " url_chain = \n\t\"%s\"\n\t" |
| 1050 " full_path = \"%" PRFilePath "\"" | 1182 " full_path = \"%" PRFilePath "\"" |
| 1051 " target_path = \"%" PRFilePath "\"", | 1183 " target_path = \"%" PRFilePath "\"" |
| 1184 " has download file = %s", |
| 1052 GetDbHandle(), | 1185 GetDbHandle(), |
| 1053 GetTotalBytes(), | 1186 GetTotalBytes(), |
| 1054 GetReceivedBytes(), | 1187 GetReceivedBytes(), |
| 1055 InterruptReasonDebugString(last_reason_).c_str(), | 1188 InterruptReasonDebugString(last_reason_).c_str(), |
| 1056 IsPaused() ? 'T' : 'F', | 1189 IsPaused() ? 'T' : 'F', |
| 1057 IsOtr() ? 'T' : 'F', | 1190 IsOtr() ? 'T' : 'F', |
| 1058 DebugSafetyStateString(GetSafetyState()), | 1191 DebugSafetyStateString(GetSafetyState()), |
| 1059 GetLastModifiedTime().c_str(), | 1192 GetLastModifiedTime().c_str(), |
| 1060 GetETag().c_str(), | 1193 GetETag().c_str(), |
| 1061 url_list.c_str(), | 1194 url_list.c_str(), |
| 1062 GetFullPath().value().c_str(), | 1195 GetFullPath().value().c_str(), |
| 1063 GetTargetFilePath().value().c_str()); | 1196 GetTargetFilePath().value().c_str(), |
| 1197 download_file_.get() ? "true" : "false"); |
| 1064 } else { | 1198 } else { |
| 1065 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); | 1199 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); |
| 1066 } | 1200 } |
| 1067 | 1201 |
| 1068 description += " }"; | 1202 description += " }"; |
| 1069 | 1203 |
| 1070 return description; | 1204 return description; |
| 1071 } | 1205 } |
| 1072 | 1206 |
| 1073 bool DownloadItemImpl::AllDataSaved() const { return all_data_saved_; } | 1207 bool DownloadItemImpl::AllDataSaved() const { return all_data_saved_; } |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1192 std::map<const void*, ExternalData*>::iterator it = | 1326 std::map<const void*, ExternalData*>::iterator it = |
| 1193 external_data_map_.find(key); | 1327 external_data_map_.find(key); |
| 1194 | 1328 |
| 1195 if (it == external_data_map_.end()) { | 1329 if (it == external_data_map_.end()) { |
| 1196 external_data_map_[key] = data; | 1330 external_data_map_[key] = data; |
| 1197 } else if (it->second != data) { | 1331 } else if (it->second != data) { |
| 1198 delete it->second; | 1332 delete it->second; |
| 1199 it->second = data; | 1333 it->second = data; |
| 1200 } | 1334 } |
| 1201 } | 1335 } |
| OLD | NEW |