OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/download/download_manager.h" | 5 #include "content/browser/download/download_manager.h" |
6 | 6 |
7 #include <iterator> | 7 #include <iterator> |
8 | 8 |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 // The user hasn't accepted it, so we need to remove it | 105 // The user hasn't accepted it, so we need to remove it |
106 // from the disk. This may or may not result in it being | 106 // from the disk. This may or may not result in it being |
107 // removed from the DownloadManager queues and deleted | 107 // removed from the DownloadManager queues and deleted |
108 // (specifically, DownloadManager::RemoveDownload only | 108 // (specifically, DownloadManager::RemoveDownload only |
109 // removes and deletes it if it's known to the history service) | 109 // removes and deletes it if it's known to the history service) |
110 // so the only thing we know after calling this function is that | 110 // so the only thing we know after calling this function is that |
111 // the download was deleted if-and-only-if it was removed | 111 // the download was deleted if-and-only-if it was removed |
112 // from all queues. | 112 // from all queues. |
113 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN); | 113 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN); |
114 } else if (download->IsPartialDownload()) { | 114 } else if (download->IsPartialDownload()) { |
115 download->Cancel(); | 115 download->Cancel(false); |
| 116 delegate_->UpdateItemInPersistentStore(download); |
116 } | 117 } |
117 } | 118 } |
118 | 119 |
119 // At this point, all dangerous downloads have had their files removed | 120 // At this point, all dangerous downloads have had their files removed |
120 // and all in progress downloads have been cancelled. We can now delete | 121 // and all in progress downloads have been cancelled. We can now delete |
121 // anything left. | 122 // anything left. |
122 | 123 |
123 // Copy downloads_ to separate container so as not to set off checks | 124 // Copy downloads_ to separate container so as not to set off checks |
124 // in DownloadItem destruction. | 125 // in DownloadItem destruction. |
125 DownloadSet downloads_to_delete; | 126 DownloadSet downloads_to_delete; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 << " download = " << download->DebugString(true); | 268 << " download = " << download->DebugString(true); |
268 | 269 |
269 FilePath suggested_path = download->suggested_path(); | 270 FilePath suggested_path = download->suggested_path(); |
270 | 271 |
271 if (download->prompt_user_for_save_location()) { | 272 if (download->prompt_user_for_save_location()) { |
272 // We must ask the user for the place to put the download. | 273 // We must ask the user for the place to put the download. |
273 DownloadRequestHandle request_handle = download->request_handle(); | 274 DownloadRequestHandle request_handle = download->request_handle(); |
274 TabContents* contents = request_handle.GetTabContents(); | 275 TabContents* contents = request_handle.GetTabContents(); |
275 | 276 |
276 // |id_ptr| will be deleted in either FileSelected() or | 277 // |id_ptr| will be deleted in either FileSelected() or |
277 // FileSelectionCanceled(). | 278 // FileSelectionCancelled(). |
278 int32* id_ptr = new int32; | 279 int32* id_ptr = new int32; |
279 *id_ptr = download_id; | 280 *id_ptr = download_id; |
280 | 281 |
281 delegate_->ChooseDownloadPath( | 282 delegate_->ChooseDownloadPath( |
282 contents, suggested_path, reinterpret_cast<void*>(id_ptr)); | 283 contents, suggested_path, reinterpret_cast<void*>(id_ptr)); |
283 | 284 |
284 FOR_EACH_OBSERVER(Observer, observers_, | 285 FOR_EACH_OBSERVER(Observer, observers_, |
285 SelectFileDialogDisplayed(download_id)); | 286 SelectFileDialogDisplayed(download_id)); |
286 } else { | 287 } else { |
287 // No prompting for download, just continue with the suggested name. | 288 // No prompting for download, just continue with the suggested name. |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 NewRunnableMethod( | 498 NewRunnableMethod( |
498 file_manager_, &DownloadFileManager::CompleteDownload, download_id)); | 499 file_manager_, &DownloadFileManager::CompleteDownload, download_id)); |
499 | 500 |
500 if (uniquifier) | 501 if (uniquifier) |
501 item->set_path_uniquifier(uniquifier); | 502 item->set_path_uniquifier(uniquifier); |
502 | 503 |
503 item->OnDownloadRenamedToFinalName(full_path); | 504 item->OnDownloadRenamedToFinalName(full_path); |
504 delegate_->UpdatePathForItemInPersistentStore(item, full_path); | 505 delegate_->UpdatePathForItemInPersistentStore(item, full_path); |
505 } | 506 } |
506 | 507 |
507 void DownloadManager::DownloadStopped(DownloadItem* download) { | 508 void DownloadManager::CancelDownload(int32 download_id) { |
| 509 DownloadItem* download = GetActiveDownload(download_id); |
| 510 // A cancel at the right time could remove the download from the |
| 511 // |active_downloads_| map before we get here. |
| 512 if (!download) |
| 513 return; |
| 514 |
| 515 download->Cancel(true); |
| 516 } |
| 517 |
| 518 void DownloadManager::DownloadCancelledInternal(DownloadItem* download) { |
508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
509 CHECK(ContainsKey(active_downloads_, download->id())); | |
510 | 520 |
511 VLOG(20) << __FUNCTION__ << "()" | 521 VLOG(20) << __FUNCTION__ << "()" |
512 << " download = " << download->DebugString(true); | 522 << " download = " << download->DebugString(true); |
513 | 523 |
514 in_progress_.erase(download->id()); | 524 RemoveFromActiveList(download); |
515 active_downloads_.erase(download->id()); | |
516 UpdateDownloadProgress(); // Reflect removal from in_progress_. | |
517 if (download->db_handle() != DownloadItem::kUninitializedHandle) | |
518 delegate_->UpdateItemInPersistentStore(download); | |
519 | |
520 // This function is called from the DownloadItem, so DI state | 525 // This function is called from the DownloadItem, so DI state |
521 // should already have been updated. | 526 // should already have been updated. |
522 AssertQueueStateConsistent(download); | 527 AssertQueueStateConsistent(download); |
523 | 528 |
524 download->OffThreadCancel(file_manager_); | 529 download->OffThreadCancel(file_manager_); |
525 } | 530 } |
526 | 531 |
527 void DownloadManager::OnDownloadError(int32 download_id, | 532 void DownloadManager::OnDownloadError(int32 download_id, |
528 int64 size, | 533 int64 size, |
529 net::Error error) { | 534 net::Error error) { |
530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 535 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
531 | 536 |
532 DownloadItem* download = GetActiveDownload(download_id); | 537 DownloadItem* download = GetActiveDownload(download_id); |
533 if (!download) | 538 if (!download) |
534 return; | 539 return; |
535 | 540 |
536 VLOG(20) << __FUNCTION__ << "()" << " Error " << error | 541 VLOG(20) << __FUNCTION__ << "()" << " Error " << error |
537 << " at offset " << download->received_bytes() | 542 << " at offset " << download->received_bytes() |
538 << " size = " << size | 543 << " size = " << size |
539 << " download = " << download->DebugString(true); | 544 << " download = " << download->DebugString(true); |
540 | 545 |
541 download->Interrupt(size, error); | 546 RemoveFromActiveList(download); |
| 547 download->Interrupted(size, error); |
| 548 download->OffThreadCancel(file_manager_); |
542 } | 549 } |
543 | 550 |
544 DownloadItem* DownloadManager::GetActiveDownload(int32 download_id) { | 551 DownloadItem* DownloadManager::GetActiveDownload(int32 download_id) { |
545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
546 DownloadMap::iterator it = active_downloads_.find(download_id); | 553 DownloadMap::iterator it = active_downloads_.find(download_id); |
547 if (it == active_downloads_.end()) | 554 if (it == active_downloads_.end()) |
548 return NULL; | 555 return NULL; |
549 | 556 |
550 DownloadItem* download = it->second; | 557 DownloadItem* download = it->second; |
551 | 558 |
552 DCHECK(download); | 559 DCHECK(download); |
553 DCHECK_EQ(download_id, download->id()); | 560 DCHECK_EQ(download_id, download->id()); |
554 | 561 |
555 return download; | 562 return download; |
556 } | 563 } |
557 | 564 |
| 565 void DownloadManager::RemoveFromActiveList(DownloadItem* download) { |
| 566 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 567 DCHECK(download); |
| 568 |
| 569 // Clean up will happen when the history system create callback runs if we |
| 570 // don't have a valid db_handle yet. |
| 571 if (download->db_handle() != DownloadItem::kUninitializedHandle) { |
| 572 in_progress_.erase(download->id()); |
| 573 active_downloads_.erase(download->id()); |
| 574 UpdateDownloadProgress(); // Reflect removal from in_progress_. |
| 575 delegate_->UpdateItemInPersistentStore(download); |
| 576 } |
| 577 } |
| 578 |
558 void DownloadManager::UpdateDownloadProgress() { | 579 void DownloadManager::UpdateDownloadProgress() { |
559 delegate_->DownloadProgressUpdated(); | 580 delegate_->DownloadProgressUpdated(); |
560 } | 581 } |
561 | 582 |
562 int DownloadManager::RemoveDownloadItems( | 583 int DownloadManager::RemoveDownloadItems( |
563 const DownloadVector& pending_deletes) { | 584 const DownloadVector& pending_deletes) { |
564 if (pending_deletes.empty()) | 585 if (pending_deletes.empty()) |
565 return 0; | 586 return 0; |
566 | 587 |
567 // Delete from internal maps. | 588 // Delete from internal maps. |
568 for (DownloadVector::const_iterator it = pending_deletes.begin(); | 589 for (DownloadVector::const_iterator it = pending_deletes.begin(); |
569 it != pending_deletes.end(); | 590 it != pending_deletes.end(); |
570 ++it) { | 591 ++it) { |
571 DownloadItem* download = *it; | 592 DownloadItem* download = *it; |
572 DCHECK(download); | 593 DCHECK(download); |
573 history_downloads_.erase(download->db_handle()); | 594 history_downloads_.erase(download->db_handle()); |
574 save_page_downloads_.erase(download->id()); | 595 save_page_downloads_.erase(download->id()); |
575 downloads_.erase(download); | 596 downloads_.erase(download); |
576 } | 597 } |
577 | 598 |
578 // Tell observers to refresh their views. | 599 // Tell observers to refresh their views. |
579 NotifyModelChanged(); | 600 NotifyModelChanged(); |
580 | 601 |
581 // Delete the download items themselves. | 602 // Delete the download items themselves. |
582 const int num_deleted = static_cast<int>(pending_deletes.size()); | 603 const int num_deleted = static_cast<int>(pending_deletes.size()); |
583 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); | 604 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); |
584 return num_deleted; | 605 return num_deleted; |
585 } | 606 } |
586 | 607 |
587 void DownloadManager::RemoveDownload(DownloadItem* download) { | 608 void DownloadManager::RemoveDownload(int64 download_handle) { |
588 // Make history update. Ignores if db_handle isn't in history. | 609 DownloadMap::iterator it = history_downloads_.find(download_handle); |
589 delegate_->RemoveItemFromPersistentStore(download->db_handle()); | 610 if (it == history_downloads_.end()) |
| 611 return; |
| 612 |
| 613 // Make history update. |
| 614 DownloadItem* download = it->second; |
| 615 delegate_->RemoveItemFromPersistentStore(download); |
590 | 616 |
591 // Remove from our tables and delete. | 617 // Remove from our tables and delete. |
592 int downloads_count = RemoveDownloadItems(DownloadVector(1, download)); | 618 int downloads_count = RemoveDownloadItems(DownloadVector(1, download)); |
593 DCHECK_EQ(1, downloads_count); | 619 DCHECK_EQ(1, downloads_count); |
594 } | 620 } |
595 | 621 |
596 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, | 622 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, |
597 const base::Time remove_end) { | 623 const base::Time remove_end) { |
598 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end); | 624 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end); |
599 | 625 |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
729 int32 download_id = *id_ptr; | 755 int32 download_id = *id_ptr; |
730 delete id_ptr; | 756 delete id_ptr; |
731 | 757 |
732 DownloadItem* download = GetActiveDownloadItem(download_id); | 758 DownloadItem* download = GetActiveDownloadItem(download_id); |
733 if (!download) | 759 if (!download) |
734 return; | 760 return; |
735 | 761 |
736 VLOG(20) << __FUNCTION__ << "()" | 762 VLOG(20) << __FUNCTION__ << "()" |
737 << " download = " << download->DebugString(true); | 763 << " download = " << download->DebugString(true); |
738 | 764 |
739 download->Cancel(); | 765 // TODO(ahendrickson) -- This currently has no effect, as the download is |
| 766 // not put on the active list until the file selection is complete. Need |
| 767 // to put it on the active list earlier in the process. |
| 768 RemoveFromActiveList(download); |
| 769 |
| 770 download->OffThreadCancel(file_manager_); |
740 } | 771 } |
741 | 772 |
742 // Operations posted to us from the history service ---------------------------- | 773 // Operations posted to us from the history service ---------------------------- |
743 | 774 |
744 // The history service has retrieved all download entries. 'entries' contains | 775 // The history service has retrieved all download entries. 'entries' contains |
745 // 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time). | 776 // 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time). |
746 void DownloadManager::OnPersistentStoreQueryComplete( | 777 void DownloadManager::OnPersistentStoreQueryComplete( |
747 std::vector<DownloadPersistentStoreInfo>* entries) { | 778 std::vector<DownloadPersistentStoreInfo>* entries) { |
748 // TODO(rdsmith): Remove this and related logic when | 779 // TODO(rdsmith): Remove this and related logic when |
749 // http://crbug.com/84508 is fixed. | 780 // http://crbug.com/84508 is fixed. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
800 // It's valid that we don't find a matching item, i.e. on shutdown. | 831 // It's valid that we don't find a matching item, i.e. on shutdown. |
801 } | 832 } |
802 | 833 |
803 // Once the new DownloadItem's creation info has been committed to the history | 834 // Once the new DownloadItem's creation info has been committed to the history |
804 // service, we associate the DownloadItem with the db handle, update our | 835 // service, we associate the DownloadItem with the db handle, update our |
805 // 'history_downloads_' map and inform observers. | 836 // 'history_downloads_' map and inform observers. |
806 void DownloadManager::OnDownloadItemAddedToPersistentStore(int32 download_id, | 837 void DownloadManager::OnDownloadItemAddedToPersistentStore(int32 download_id, |
807 int64 db_handle) { | 838 int64 db_handle) { |
808 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 839 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
809 DownloadItem* download = GetActiveDownloadItem(download_id); | 840 DownloadItem* download = GetActiveDownloadItem(download_id); |
810 if (!download) { | 841 if (!download) |
811 // The download was cancelled while the persistent store was entering it. | |
812 // We resolve this race by turning around and deleting it in the | |
813 // persistent store (implicitly treating it as a failure in download | |
814 // initiation, which is appropriate as the only places the cancel could | |
815 // have come from were in resolving issues (like the file name) which | |
816 // we need to have resolved for persistent store insertion). | |
817 | |
818 // Make sure we haven't already been shutdown (the callback raced | |
819 // with shutdown), as that would mean that we no longer have access | |
820 // to the persistent store. In that case, the history will be cleaned up | |
821 // on next persistent store query. | |
822 if (shutdown_needed_) | |
823 delegate_->RemoveItemFromPersistentStore(db_handle); | |
824 return; | 842 return; |
825 } | |
826 | 843 |
827 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle | 844 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle |
828 << " download_id = " << download_id | 845 << " download_id = " << download_id |
829 << " download = " << download->DebugString(true); | 846 << " download = " << download->DebugString(true); |
830 | 847 |
831 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved. | 848 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved. |
832 int64 largest_handle = largest_db_handle_in_history_; | 849 int64 largest_handle = largest_db_handle_in_history_; |
833 base::debug::Alias(&largest_handle); | 850 base::debug::Alias(&largest_handle); |
834 int32 matching_item_download_id | 851 int32 matching_item_download_id |
835 = (ContainsKey(history_downloads_, db_handle) ? | 852 = (ContainsKey(history_downloads_, db_handle) ? |
836 history_downloads_[db_handle]->id() : 0); | 853 history_downloads_[db_handle]->id() : 0); |
837 base::debug::Alias(&matching_item_download_id); | 854 base::debug::Alias(&matching_item_download_id); |
838 | 855 |
839 CHECK(!ContainsKey(history_downloads_, db_handle)); | 856 CHECK(!ContainsKey(history_downloads_, db_handle)); |
840 | 857 |
841 CHECK(download->IsInProgress()); | |
842 AddDownloadItemToHistory(download, db_handle); | 858 AddDownloadItemToHistory(download, db_handle); |
843 | 859 |
844 MaybeCompleteDownload(download); | 860 // If the download is still in progress, try to complete it. |
| 861 // |
| 862 // Otherwise, download has been cancelled or interrupted before we've |
| 863 // received the DB handle. We post one final message to the history |
| 864 // service so that it can be properly in sync with the DownloadItem's |
| 865 // completion status, and also inform any observers so that they get |
| 866 // more than just the start notification. |
| 867 if (download->IsInProgress()) { |
| 868 MaybeCompleteDownload(download); |
| 869 } else { |
| 870 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508 |
| 871 // is fixed. |
| 872 CHECK(download->IsCancelled()) |
| 873 << " download = " << download->DebugString(true); |
| 874 in_progress_.erase(download_id); |
| 875 active_downloads_.erase(download_id); |
| 876 delegate_->UpdateItemInPersistentStore(download); |
| 877 download->UpdateObservers(); |
| 878 } |
845 } | 879 } |
846 | 880 |
847 void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) { | 881 void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) { |
848 // The 'contents' may no longer exist if the user closed the tab before we | 882 // The 'contents' may no longer exist if the user closed the tab before we |
849 // get this start completion event. | 883 // get this start completion event. |
850 DownloadRequestHandle request_handle = download->request_handle(); | 884 DownloadRequestHandle request_handle = download->request_handle(); |
851 TabContents* content = request_handle.GetTabContents(); | 885 TabContents* content = request_handle.GetTabContents(); |
852 | 886 |
853 // If the contents no longer exists, we ask the embedder to suggest another | 887 // If the contents no longer exists, we ask the embedder to suggest another |
854 // tab. | 888 // tab. |
(...skipping 18 matching lines...) Expand all Loading... |
873 // not its id, so we have to iterate. | 907 // not its id, so we have to iterate. |
874 for (DownloadMap::iterator it = history_downloads_.begin(); | 908 for (DownloadMap::iterator it = history_downloads_.begin(); |
875 it != history_downloads_.end(); ++it) { | 909 it != history_downloads_.end(); ++it) { |
876 DownloadItem* item = it->second; | 910 DownloadItem* item = it->second; |
877 if (item->id() == download_id) | 911 if (item->id() == download_id) |
878 return item; | 912 return item; |
879 } | 913 } |
880 return NULL; | 914 return NULL; |
881 } | 915 } |
882 | 916 |
883 void DownloadManager::GetInProgressDownloads( | |
884 std::vector<DownloadItem*>* result) { | |
885 DCHECK(result); | |
886 | |
887 for (DownloadMap::iterator it = active_downloads_.begin(); | |
888 it != active_downloads_.end(); ++it) { | |
889 result->push_back(it->second); | |
890 } | |
891 } | |
892 | |
893 DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) { | 917 DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) { |
894 if (!ContainsKey(active_downloads_, download_id)) | 918 DCHECK(ContainsKey(active_downloads_, download_id)); |
895 return NULL; | |
896 | |
897 DownloadItem* download = active_downloads_[download_id]; | 919 DownloadItem* download = active_downloads_[download_id]; |
898 DCHECK(download != NULL); | 920 DCHECK(download != NULL); |
899 return download; | 921 return download; |
900 } | 922 } |
901 | 923 |
902 // Confirm that everything in all maps is also in |downloads_|, and that | 924 // Confirm that everything in all maps is also in |downloads_|, and that |
903 // everything in |downloads_| is also in some other map. | 925 // everything in |downloads_| is also in some other map. |
904 void DownloadManager::AssertContainersConsistent() const { | 926 void DownloadManager::AssertContainersConsistent() const { |
905 #if !defined(NDEBUG) | 927 #if !defined(NDEBUG) |
906 // Turn everything into sets. | 928 // Turn everything into sets. |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1002 DCHECK(ContainsKey(save_page_downloads_, download->id())); | 1024 DCHECK(ContainsKey(save_page_downloads_, download->id())); |
1003 save_page_downloads_.erase(download->id()); | 1025 save_page_downloads_.erase(download->id()); |
1004 | 1026 |
1005 if (download->IsComplete()) | 1027 if (download->IsComplete()) |
1006 NotificationService::current()->Notify( | 1028 NotificationService::current()->Notify( |
1007 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, | 1029 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
1008 Source<DownloadManager>(this), | 1030 Source<DownloadManager>(this), |
1009 Details<DownloadItem>(download)); | 1031 Details<DownloadItem>(download)); |
1010 } | 1032 } |
1011 } | 1033 } |
OLD | NEW |