Chromium Code Reviews| 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 // Wrapper around DownloadFile::Detach and DownloadFile::Cancel that | |
| 122 // takes ownership of the DownloadFile and hence implicitly destroys it | |
| 123 // at the end of the function. | |
|
benjhayden
2012/08/16 20:35:20
Please also warn against copying callbacks contain
Randy Smith (Not in Mondays)
2012/08/16 20:44:21
I apologize, but I think I'm going to take your ou
| |
| 124 static void DownloadFileDetach(scoped_ptr<DownloadFile> download_file) { | |
| 125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 126 download_file->Detach(); | |
| 127 } | |
| 128 | |
| 129 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) { | |
| 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 131 download_file->Cancel(); | |
| 132 } | |
| 133 | |
| 122 } // namespace | 134 } // namespace |
| 123 | 135 |
| 124 namespace content { | 136 namespace content { |
| 125 | 137 |
| 126 // Our download table ID starts at 1, so we use 0 to represent a download that | 138 // 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 | 139 // 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 | 140 // database handles in incognito mode starting at -1 and progressively getting |
| 129 // more negative. | 141 // more negative. |
| 130 // static | 142 // static |
| 131 const int DownloadItem::kUninitializedHandle = 0; | 143 const int DownloadItem::kUninitializedHandle = 0; |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 delegate_delayed_complete_(false), | 297 delegate_delayed_complete_(false), |
| 286 bound_net_log_(bound_net_log), | 298 bound_net_log_(bound_net_log), |
| 287 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | 299 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
| 288 delegate_->Attach(); | 300 delegate_->Attach(); |
| 289 Init(true /* actively downloading */, | 301 Init(true /* actively downloading */, |
| 290 download_net_logs::SRC_SAVE_PAGE_AS); | 302 download_net_logs::SRC_SAVE_PAGE_AS); |
| 291 } | 303 } |
| 292 | 304 |
| 293 DownloadItemImpl::~DownloadItemImpl() { | 305 DownloadItemImpl::~DownloadItemImpl() { |
| 294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 307 | |
| 308 // Should always have been nuked before now, at worst in | |
| 309 // DownloadManager shutdown. | |
| 310 DCHECK(!download_file_.get()); | |
| 311 | |
| 295 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this)); | 312 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this)); |
| 296 delegate_->AssertStateConsistent(this); | 313 delegate_->AssertStateConsistent(this); |
| 297 delegate_->Detach(); | 314 delegate_->Detach(); |
| 298 } | 315 } |
| 299 | 316 |
| 317 base::WeakPtr<content::DownloadDestinationObserver> | |
| 318 DownloadItemImpl::DestinationObserverAsWeakPtr() { | |
| 319 // Return does private downcast. | |
| 320 return weak_ptr_factory_.GetWeakPtr(); | |
| 321 } | |
| 322 | |
| 300 void DownloadItemImpl::AddObserver(Observer* observer) { | 323 void DownloadItemImpl::AddObserver(Observer* observer) { |
| 301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 302 | 325 |
| 303 observers_.AddObserver(observer); | 326 observers_.AddObserver(observer); |
| 304 } | 327 } |
| 305 | 328 |
| 306 void DownloadItemImpl::RemoveObserver(Observer* observer) { | 329 void DownloadItemImpl::RemoveObserver(Observer* observer) { |
| 307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 308 | 331 |
| 309 observers_.RemoveObserver(observer); | 332 observers_.RemoveObserver(observer); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 bound_net_log_.AddEvent( | 401 bound_net_log_.AddEvent( |
| 379 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, | 402 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, |
| 380 base::Bind(&download_net_logs::ItemCheckedCallback, | 403 base::Bind(&download_net_logs::ItemCheckedCallback, |
| 381 GetDangerType(), GetSafetyState())); | 404 GetDangerType(), GetSafetyState())); |
| 382 | 405 |
| 383 UpdateObservers(); | 406 UpdateObservers(); |
| 384 | 407 |
| 385 delegate_->MaybeCompleteDownload(this); | 408 delegate_->MaybeCompleteDownload(this); |
| 386 } | 409 } |
| 387 | 410 |
| 388 void DownloadItemImpl::ProgressComplete(int64 bytes_so_far, | |
| 389 const std::string& final_hash) { | |
| 390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 391 | |
| 392 hash_ = final_hash; | |
| 393 hash_state_ = ""; | |
| 394 | |
| 395 received_bytes_ = bytes_so_far; | |
| 396 | |
| 397 // If we've received more data than we were expecting (bad server info?), | |
| 398 // revert to 'unknown size mode'. | |
| 399 if (received_bytes_ > total_bytes_) | |
| 400 total_bytes_ = 0; | |
| 401 } | |
| 402 | |
| 403 // Updates from the download thread may have been posted while this download | 411 // Updates from the download thread may have been posted while this download |
| 404 // was being cancelled in the UI thread, so we'll accept them unless we're | 412 // was being cancelled in the UI thread, so we'll accept them unless we're |
| 405 // complete. | 413 // complete. |
| 406 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, | 414 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, |
| 407 int64 bytes_per_sec, | 415 int64 bytes_per_sec, |
| 408 const std::string& hash_state) { | 416 const std::string& hash_state) { |
| 409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 410 | 418 |
| 411 if (!IsInProgress()) { | 419 if (!IsInProgress()) { |
| 412 // Ignore if we're no longer in-progress. This can happen if we race a | 420 // 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... | |
| 449 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); | 457 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
| 450 if (!IsPartialDownload()) { | 458 if (!IsPartialDownload()) { |
| 451 // Small downloads might be complete before this method has | 459 // Small downloads might be complete before this method has |
| 452 // a chance to run. | 460 // a chance to run. |
| 453 return; | 461 return; |
| 454 } | 462 } |
| 455 | 463 |
| 456 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); | 464 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); |
| 457 | 465 |
| 458 TransitionTo(CANCELLED); | 466 TransitionTo(CANCELLED); |
| 467 | |
| 468 // Cancel and remove the download file. | |
| 469 DCHECK(download_file_.get()); | |
| 470 BrowserThread::PostTask( | |
| 471 BrowserThread::FILE, FROM_HERE, | |
| 472 // Will be deleted at end of task execution. | |
| 473 base::Bind(&DownloadFileCancel, base::Passed(download_file_.Pass()))); | |
| 474 | |
| 475 // Cancel the originating URL request. | |
| 476 request_handle_->CancelRequest(); | |
| 477 | |
| 459 if (user_cancel) | 478 if (user_cancel) |
| 460 delegate_->DownloadStopped(this); | 479 delegate_->DownloadStopped(this); |
| 461 } | 480 } |
| 462 | 481 |
| 482 // We're starting the download. | |
| 483 void DownloadItemImpl::Start(scoped_ptr<content::DownloadFile> download_file) { | |
| 484 DCHECK(!download_file_.get()); | |
| 485 download_file_ = download_file.Pass(); | |
| 486 | |
| 487 BrowserThread::PostTask( | |
| 488 BrowserThread::FILE, FROM_HERE, | |
| 489 base::Bind(&DownloadFile::Initialize, | |
| 490 // Safe because we control download file lifetime. | |
| 491 base::Unretained(download_file_.get()), | |
| 492 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, | |
| 493 weak_ptr_factory_.GetWeakPtr()))); | |
| 494 } | |
| 495 | |
| 463 // An error occurred somewhere. | 496 // An error occurred somewhere. |
| 464 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { | 497 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { |
| 465 // Somewhat counter-intuitively, it is possible for us to receive an | 498 // Somewhat counter-intuitively, it is possible for us to receive an |
| 466 // interrupt after we've already been interrupted. The generation of | 499 // interrupt after we've already been interrupted. The generation of |
| 467 // interrupts from the file thread Renames and the generation of | 500 // interrupts from the file thread Renames and the generation of |
| 468 // interrupts from disk writes go through two different mechanisms (driven | 501 // interrupts from disk writes go through two different mechanisms (driven |
| 469 // by rename requests from UI thread and by write requests from IO thread, | 502 // by rename requests from UI thread and by write requests from IO thread, |
| 470 // respectively), and since we choose not to keep state on the File thread, | 503 // respectively), and since we choose not to keep state on the File thread, |
| 471 // this is the place where the races collide. It's also possible for | 504 // this is the place where the races collide. It's also possible for |
| 472 // interrupts to race with cancels. | 505 // interrupts to race with cancels. |
| 473 | 506 |
| 474 // Whatever happens, the first one to hit the UI thread wins. | 507 // Whatever happens, the first one to hit the UI thread wins. |
| 475 if (!IsInProgress()) | 508 if (!IsInProgress()) |
| 476 return; | 509 return; |
| 477 | 510 |
| 478 last_reason_ = reason; | 511 last_reason_ = reason; |
| 479 TransitionTo(INTERRUPTED); | 512 TransitionTo(INTERRUPTED); |
| 513 | |
| 514 // Cancel and remove the download file. | |
| 515 DCHECK(download_file_.get()); | |
| 516 BrowserThread::PostTask( | |
| 517 BrowserThread::FILE, FROM_HERE, | |
| 518 // Will be deleted at end of task execution. | |
| 519 base::Bind(&DownloadFileCancel, base::Passed(download_file_.Pass()))); | |
| 520 | |
| 521 // Cancel the originating URL request. | |
| 522 request_handle_->CancelRequest(); | |
| 523 | |
| 480 download_stats::RecordDownloadInterrupted( | 524 download_stats::RecordDownloadInterrupted( |
| 481 reason, received_bytes_, total_bytes_); | 525 reason, received_bytes_, total_bytes_); |
| 482 delegate_->DownloadStopped(this); | 526 delegate_->DownloadStopped(this); |
| 483 } | 527 } |
| 484 | 528 |
| 485 void DownloadItemImpl::MarkAsComplete() { | 529 void DownloadItemImpl::MarkAsComplete() { |
| 486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 487 | 531 |
| 488 DCHECK(all_data_saved_); | 532 DCHECK(all_data_saved_); |
| 489 end_time_ = base::Time::Now(); | 533 end_time_ = base::Time::Now(); |
| 490 TransitionTo(COMPLETE); | 534 TransitionTo(COMPLETE); |
| 491 } | 535 } |
| 492 | 536 |
| 493 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { | 537 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { |
| 494 auto_opened_ = auto_opened; | 538 auto_opened_ = auto_opened; |
| 495 Completed(); | 539 Completed(); |
| 496 } | 540 } |
| 497 | 541 |
| 498 void DownloadItemImpl::OnAllDataSaved( | 542 void DownloadItemImpl::OnAllDataSaved( |
| 499 int64 size, const std::string& final_hash) { | 543 const std::string& final_hash) { |
| 500 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 544 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 501 | 545 |
| 546 DCHECK_EQ(IN_PROGRESS, state_); | |
| 502 DCHECK(!all_data_saved_); | 547 DCHECK(!all_data_saved_); |
| 503 all_data_saved_ = true; | 548 all_data_saved_ = true; |
| 504 ProgressComplete(size, final_hash); | 549 |
| 550 // Store final hash and null out intermediate serialized hash state. | |
| 551 hash_ = final_hash; | |
| 552 hash_state_ = ""; | |
| 553 | |
| 505 UpdateObservers(); | 554 UpdateObservers(); |
| 506 } | 555 } |
| 507 | 556 |
| 508 void DownloadItemImpl::OnDownloadedFileRemoved() { | 557 void DownloadItemImpl::OnDownloadedFileRemoved() { |
| 509 file_externally_removed_ = true; | 558 file_externally_removed_ = true; |
| 510 UpdateObservers(); | 559 UpdateObservers(); |
| 511 } | 560 } |
| 512 | 561 |
| 513 void DownloadItemImpl::MaybeCompleteDownload() { | 562 void DownloadItemImpl::MaybeCompleteDownload() { |
| 514 // TODO(rdsmith): Move logic for this function here. | 563 // TODO(rdsmith): Move logic for this function here. |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 689 request_handle_->ResumeRequest(); | 738 request_handle_->ResumeRequest(); |
| 690 else | 739 else |
| 691 request_handle_->PauseRequest(); | 740 request_handle_->PauseRequest(); |
| 692 is_paused_ = !is_paused_; | 741 is_paused_ = !is_paused_; |
| 693 UpdateObservers(); | 742 UpdateObservers(); |
| 694 } | 743 } |
| 695 | 744 |
| 696 void DownloadItemImpl::OnDownloadCompleting() { | 745 void DownloadItemImpl::OnDownloadCompleting() { |
| 697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 746 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 698 | 747 |
| 748 if (!IsInProgress()) | |
| 749 return; | |
| 750 | |
| 699 VLOG(20) << __FUNCTION__ << "()" | 751 VLOG(20) << __FUNCTION__ << "()" |
| 700 << " needs rename = " << NeedsRename() | 752 << " needs rename = " << NeedsRename() |
| 701 << " " << DebugString(true); | 753 << " " << DebugString(true); |
| 702 DCHECK(!GetTargetName().empty()); | 754 DCHECK(!GetTargetName().empty()); |
| 703 DCHECK_NE(DANGEROUS, GetSafetyState()); | 755 DCHECK_NE(DANGEROUS, GetSafetyState()); |
| 704 | 756 |
| 757 DCHECK(download_file_.get()); | |
| 705 if (NeedsRename()) { | 758 if (NeedsRename()) { |
| 706 DownloadFileManager::RenameCompletionCallback callback = | 759 content::DownloadFile::RenameCompletionCallback callback = |
| 707 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, | 760 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, |
| 708 weak_ptr_factory_.GetWeakPtr()); | 761 weak_ptr_factory_.GetWeakPtr()); |
| 709 BrowserThread::PostTask( | 762 BrowserThread::PostTask( |
| 710 BrowserThread::FILE, FROM_HERE, | 763 BrowserThread::FILE, FROM_HERE, |
| 711 base::Bind(&DownloadFileManager::RenameDownloadFile, | 764 base::Bind(&DownloadFile::Rename, |
| 712 delegate_->GetDownloadFileManager(), GetGlobalId(), | 765 base::Unretained(download_file_.get()), |
| 713 GetTargetFilePath(), true, callback)); | 766 GetTargetFilePath(), true, callback)); |
| 714 } else { | 767 } else { |
| 715 // Complete the download and release the DownloadFile. | 768 // Complete the download and release the DownloadFile. |
| 716 BrowserThread::PostTask( | 769 BrowserThread::PostTaskAndReply( |
| 717 BrowserThread::FILE, FROM_HERE, | 770 BrowserThread::FILE, FROM_HERE, |
| 718 base::Bind(&DownloadFileManager::CompleteDownload, | 771 base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass())), |
| 719 delegate_->GetDownloadFileManager(), GetGlobalId(), | 772 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
| 720 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | 773 weak_ptr_factory_.GetWeakPtr())); |
| 721 weak_ptr_factory_.GetWeakPtr()))); | |
| 722 } | 774 } |
| 723 } | 775 } |
| 724 | 776 |
| 725 void DownloadItemImpl::OnDownloadRenamedToFinalName( | 777 void DownloadItemImpl::OnDownloadRenamedToFinalName( |
| 726 content::DownloadInterruptReason reason, | 778 content::DownloadInterruptReason reason, |
| 727 const FilePath& full_path) { | 779 const FilePath& full_path) { |
| 728 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 780 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 729 | 781 |
| 782 if (!IsInProgress()) | |
| 783 return; | |
| 784 | |
| 730 VLOG(20) << __FUNCTION__ << "()" | 785 VLOG(20) << __FUNCTION__ << "()" |
| 731 << " full_path = \"" << full_path.value() << "\"" | 786 << " full_path = \"" << full_path.value() << "\"" |
| 732 << " needed rename = " << NeedsRename() | 787 << " needed rename = " << NeedsRename() |
| 733 << " " << DebugString(false); | 788 << " " << DebugString(false); |
| 734 DCHECK(NeedsRename()); | 789 DCHECK(NeedsRename()); |
| 735 | 790 |
| 736 if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 791 if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
| 737 Interrupt(reason); | 792 Interrupt(reason); |
| 738 return; | 793 return; |
| 739 } | 794 } |
| 740 | 795 |
| 741 // full_path is now the current and target file path. | 796 // full_path is now the current and target file path. |
| 742 DCHECK(!full_path.empty()); | 797 DCHECK(!full_path.empty()); |
| 743 target_path_ = full_path; | 798 target_path_ = full_path; |
| 744 SetFullPath(full_path); | 799 SetFullPath(full_path); |
| 745 delegate_->DownloadRenamedToFinalName(this); | 800 delegate_->DownloadRenamedToFinalName(this); |
| 746 | 801 |
| 747 // Complete the download and release the DownloadFile. | 802 // Complete the download and release the DownloadFile. |
| 748 BrowserThread::PostTask( | 803 // TODO(rdsmith): Unify this path with the !NeedsRename() path in |
| 804 // OnDownloadCompleting above. This can happen easily after history | |
| 805 // is made into an observer and the path accessors are cleaned up; | |
| 806 // that should allow OnDownloadCompleting to simply call | |
| 807 // OnDownloadRenamedToFinalName directly. | |
| 808 DCHECK(download_file_.get()); | |
| 809 BrowserThread::PostTaskAndReply( | |
| 749 BrowserThread::FILE, FROM_HERE, | 810 BrowserThread::FILE, FROM_HERE, |
| 750 base::Bind(&DownloadFileManager::CompleteDownload, | 811 base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass())), |
| 751 delegate_->GetDownloadFileManager(), GetGlobalId(), | 812 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
| 752 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | 813 weak_ptr_factory_.GetWeakPtr())); |
| 753 weak_ptr_factory_.GetWeakPtr()))); | 814 } |
| 815 | |
| 816 void DownloadItemImpl::OnDownloadFileInitialized( | |
| 817 content::DownloadInterruptReason result) { | |
| 818 if (result != content::DOWNLOAD_INTERRUPT_REASON_NONE) { | |
| 819 Interrupt(result); | |
| 820 // TODO(rdsmith): It makes no sense to continue along the | |
| 821 // regular download path after we've gotten an error. But it's | |
| 822 // the way the code has historically worked, and this allows us | |
| 823 // to get the download persisted and observers of the download manager | |
| 824 // notified, so tests work. When we execute all side effects of cancel | |
| 825 // (including queue removal) immedately rather than waiting for | |
| 826 // persistence we should replace this comment with a "return;". | |
| 827 } | |
| 828 | |
| 829 delegate_->DelegateStart(this); | |
| 754 } | 830 } |
| 755 | 831 |
| 756 void DownloadItemImpl::OnDownloadFileReleased() { | 832 void DownloadItemImpl::OnDownloadFileReleased() { |
| 757 if (delegate_->ShouldOpenDownload(this)) | 833 if (delegate_->ShouldOpenDownload(this)) |
| 758 Completed(); | 834 Completed(); |
| 759 else | 835 else |
| 760 delegate_delayed_complete_ = true; | 836 delegate_delayed_complete_ = true; |
| 761 } | 837 } |
| 762 | 838 |
| 763 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( | 839 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 874 target_path_ = target_path; | 950 target_path_ = target_path; |
| 875 target_disposition_ = disposition; | 951 target_disposition_ = disposition; |
| 876 SetDangerType(danger_type); | 952 SetDangerType(danger_type); |
| 877 // TODO(asanka): SetDangerType() doesn't need to send a notification here. | 953 // TODO(asanka): SetDangerType() doesn't need to send a notification here. |
| 878 | 954 |
| 879 // We want the intermediate and target paths to refer to the same directory so | 955 // We want the intermediate and target paths to refer to the same directory so |
| 880 // that they are both on the same device and subject to same | 956 // that they are both on the same device and subject to same |
| 881 // space/permission/availability constraints. | 957 // space/permission/availability constraints. |
| 882 DCHECK(intermediate_path.DirName() == target_path.DirName()); | 958 DCHECK(intermediate_path.DirName() == target_path.DirName()); |
| 883 | 959 |
| 960 if (!IsInProgress()) { | |
| 961 // If we've been cancelled or interrupted while the target was being | |
| 962 // determined, continue the cascade with a null name. | |
| 963 // The error doesn't matter as the cause of download stoppaged | |
| 964 // will already have been recorded. | |
| 965 OnDownloadRenamedToIntermediateName( | |
| 966 content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, FilePath()); | |
| 967 return; | |
| 968 } | |
| 969 | |
| 884 // Rename to intermediate name. | 970 // Rename to intermediate name. |
| 885 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a | 971 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a |
| 886 // spurious rename when we can just rename to the final | 972 // spurious rename when we can just rename to the final |
| 887 // filename. Unnecessary renames may cause bugs like | 973 // filename. Unnecessary renames may cause bugs like |
| 888 // http://crbug.com/74187. | 974 // http://crbug.com/74187. |
| 889 DownloadFileManager::RenameCompletionCallback callback = | 975 DCHECK(download_file_.get()); |
| 976 DownloadFile::RenameCompletionCallback callback = | |
| 890 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, | 977 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, |
| 891 weak_ptr_factory_.GetWeakPtr()); | 978 weak_ptr_factory_.GetWeakPtr()); |
| 892 BrowserThread::PostTask( | 979 BrowserThread::PostTask( |
| 893 BrowserThread::FILE, FROM_HERE, | 980 BrowserThread::FILE, FROM_HERE, |
| 894 base::Bind(&DownloadFileManager::RenameDownloadFile, | 981 base::Bind(&DownloadFile::Rename, |
| 895 delegate_->GetDownloadFileManager(), GetGlobalId(), | 982 // Safe because we control download file lifetime. |
| 983 base::Unretained(download_file_.get()), | |
| 896 intermediate_path, false, callback)); | 984 intermediate_path, false, callback)); |
| 897 } | 985 } |
| 898 | 986 |
| 899 void DownloadItemImpl::OnContentCheckCompleted( | 987 void DownloadItemImpl::OnContentCheckCompleted( |
| 900 content::DownloadDangerType danger_type) { | 988 content::DownloadDangerType danger_type) { |
| 901 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 989 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 902 DCHECK(AllDataSaved()); | 990 DCHECK(AllDataSaved()); |
| 903 SetDangerType(danger_type); | 991 SetDangerType(danger_type); |
| 904 UpdateObservers(); | 992 UpdateObservers(); |
| 905 } | 993 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 916 | 1004 |
| 917 void DownloadItemImpl::SetDisplayName(const FilePath& name) { | 1005 void DownloadItemImpl::SetDisplayName(const FilePath& name) { |
| 918 display_name_ = name; | 1006 display_name_ = name; |
| 919 } | 1007 } |
| 920 | 1008 |
| 921 FilePath DownloadItemImpl::GetUserVerifiedFilePath() const { | 1009 FilePath DownloadItemImpl::GetUserVerifiedFilePath() const { |
| 922 return (safety_state_ == DownloadItem::SAFE) ? | 1010 return (safety_state_ == DownloadItem::SAFE) ? |
| 923 GetTargetFilePath() : GetFullPath(); | 1011 GetTargetFilePath() : GetFullPath(); |
| 924 } | 1012 } |
| 925 | 1013 |
| 926 void DownloadItemImpl::OffThreadCancel() { | 1014 void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far, |
| 1015 int64 bytes_per_sec, | |
| 1016 const std::string& hash_state) { | |
| 927 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1017 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 928 request_handle_->CancelRequest(); | |
| 929 | 1018 |
| 930 BrowserThread::PostTask( | 1019 if (!IsInProgress()) { |
| 931 BrowserThread::FILE, FROM_HERE, | 1020 // Ignore if we're no longer in-progress. This can happen if we race a |
| 932 base::Bind(&DownloadFileManager::CancelDownload, | 1021 // Cancel on the UI thread with an update on the FILE thread. |
| 933 delegate_->GetDownloadFileManager(), download_id_)); | 1022 // |
| 1023 // TODO(rdsmith): Arguably we should let this go through, as this means | |
| 1024 // the download really did get further than we know before it was | |
| 1025 // cancelled. But the gain isn't very large, and the code is more | |
| 1026 // fragile if it has to support in progress updates in a non-in-progress | |
| 1027 // state. This issue should be readdressed when we revamp performance | |
| 1028 // reporting. | |
| 1029 return; | |
| 1030 } | |
| 1031 bytes_per_sec_ = bytes_per_sec; | |
| 1032 hash_state_ = hash_state; | |
| 1033 received_bytes_ = bytes_so_far; | |
| 1034 | |
| 1035 // If we've received more data than we were expecting (bad server info?), | |
| 1036 // revert to 'unknown size mode'. | |
| 1037 if (received_bytes_ > total_bytes_) | |
| 1038 total_bytes_ = 0; | |
| 1039 | |
| 1040 if (bound_net_log_.IsLoggingAllEvents()) { | |
| 1041 bound_net_log_.AddEvent( | |
| 1042 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED, | |
| 1043 net::NetLog::Int64Callback("bytes_so_far", received_bytes_)); | |
| 1044 } | |
| 1045 | |
| 1046 UpdateObservers(); | |
| 1047 } | |
| 1048 | |
| 1049 void DownloadItemImpl::DestinationError( | |
| 1050 content::DownloadInterruptReason reason) { | |
| 1051 // The DestinationError and Interrupt routines are being kept separate | |
| 1052 // to allow for a future merging of the Cancel and Interrupt routines.. | |
| 1053 Interrupt(reason); | |
| 1054 } | |
| 1055 | |
| 1056 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { | |
| 1057 if (!IsInProgress()) | |
| 1058 return; | |
| 1059 OnAllDataSaved(final_hash); | |
| 1060 delegate_->MaybeCompleteDownload(this); | |
| 934 } | 1061 } |
| 935 | 1062 |
| 936 void DownloadItemImpl::Init(bool active, | 1063 void DownloadItemImpl::Init(bool active, |
| 937 download_net_logs::DownloadType download_type) { | 1064 download_net_logs::DownloadType download_type) { |
| 938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1065 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 939 | 1066 |
| 940 if (active) | 1067 if (active) |
| 941 download_stats::RecordDownloadCount(download_stats::START_COUNT); | 1068 download_stats::RecordDownloadCount(download_stats::START_COUNT); |
| 942 | 1069 |
| 943 if (target_path_.empty()) | 1070 if (target_path_.empty()) |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1033 " db_handle = %" PRId64 | 1160 " db_handle = %" PRId64 |
| 1034 " total = %" PRId64 | 1161 " total = %" PRId64 |
| 1035 " received = %" PRId64 | 1162 " received = %" PRId64 |
| 1036 " reason = %s" | 1163 " reason = %s" |
| 1037 " paused = %c" | 1164 " paused = %c" |
| 1038 " safety = %s" | 1165 " safety = %s" |
| 1039 " last_modified = '%s'" | 1166 " last_modified = '%s'" |
| 1040 " etag = '%s'" | 1167 " etag = '%s'" |
| 1041 " url_chain = \n\t\"%s\"\n\t" | 1168 " url_chain = \n\t\"%s\"\n\t" |
| 1042 " full_path = \"%" PRFilePath "\"" | 1169 " full_path = \"%" PRFilePath "\"" |
| 1043 " target_path = \"%" PRFilePath "\"", | 1170 " target_path = \"%" PRFilePath "\"" |
| 1171 " has download file = %s", | |
| 1044 GetDbHandle(), | 1172 GetDbHandle(), |
| 1045 GetTotalBytes(), | 1173 GetTotalBytes(), |
| 1046 GetReceivedBytes(), | 1174 GetReceivedBytes(), |
| 1047 InterruptReasonDebugString(last_reason_).c_str(), | 1175 InterruptReasonDebugString(last_reason_).c_str(), |
| 1048 IsPaused() ? 'T' : 'F', | 1176 IsPaused() ? 'T' : 'F', |
| 1049 DebugSafetyStateString(GetSafetyState()), | 1177 DebugSafetyStateString(GetSafetyState()), |
| 1050 GetLastModifiedTime().c_str(), | 1178 GetLastModifiedTime().c_str(), |
| 1051 GetETag().c_str(), | 1179 GetETag().c_str(), |
| 1052 url_list.c_str(), | 1180 url_list.c_str(), |
| 1053 GetFullPath().value().c_str(), | 1181 GetFullPath().value().c_str(), |
| 1054 GetTargetFilePath().value().c_str()); | 1182 GetTargetFilePath().value().c_str(), |
| 1183 download_file_.get() ? "true" : "false"); | |
| 1055 } else { | 1184 } else { |
| 1056 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); | 1185 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); |
| 1057 } | 1186 } |
| 1058 | 1187 |
| 1059 description += " }"; | 1188 description += " }"; |
| 1060 | 1189 |
| 1061 return description; | 1190 return description; |
| 1062 } | 1191 } |
| 1063 | 1192 |
| 1064 bool DownloadItemImpl::AllDataSaved() const { return all_data_saved_; } | 1193 bool DownloadItemImpl::AllDataSaved() const { return all_data_saved_; } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1154 void DownloadItemImpl::SetOpened(bool opened) { opened_ = opened; } | 1283 void DownloadItemImpl::SetOpened(bool opened) { opened_ = opened; } |
| 1155 bool DownloadItemImpl::GetOpened() const { return opened_; } | 1284 bool DownloadItemImpl::GetOpened() const { return opened_; } |
| 1156 const std::string& DownloadItemImpl::GetLastModifiedTime() const { | 1285 const std::string& DownloadItemImpl::GetLastModifiedTime() const { |
| 1157 return last_modified_time_; | 1286 return last_modified_time_; |
| 1158 } | 1287 } |
| 1159 const std::string& DownloadItemImpl::GetETag() const { return etag_; } | 1288 const std::string& DownloadItemImpl::GetETag() const { return etag_; } |
| 1160 content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const { | 1289 content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const { |
| 1161 return last_reason_; | 1290 return last_reason_; |
| 1162 } | 1291 } |
| 1163 void DownloadItemImpl::MockDownloadOpenForTesting() { open_enabled_ = false; } | 1292 void DownloadItemImpl::MockDownloadOpenForTesting() { open_enabled_ = false; } |
| OLD | NEW |