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_manager_impl.h" | 5 #include "content/browser/download/download_manager_impl.h" |
6 | 6 |
7 #include <iterator> | 7 #include <iterator> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 | 44 |
45 using content::BrowserThread; | 45 using content::BrowserThread; |
46 using content::DownloadId; | 46 using content::DownloadId; |
47 using content::DownloadItem; | 47 using content::DownloadItem; |
48 using content::DownloadPersistentStoreInfo; | 48 using content::DownloadPersistentStoreInfo; |
49 using content::ResourceDispatcherHostImpl; | 49 using content::ResourceDispatcherHostImpl; |
50 using content::WebContents; | 50 using content::WebContents; |
51 | 51 |
52 namespace { | 52 namespace { |
53 | 53 |
| 54 // This is just used to remember which DownloadItems come from SavePage. |
| 55 class SavePageExternalData : public DownloadItem::ExternalData { |
| 56 public: |
| 57 // A spoonful of syntactic sugar. |
| 58 static bool Get(DownloadItem* item) { |
| 59 return item->GetExternalData(kKey) != NULL; |
| 60 } |
| 61 |
| 62 explicit SavePageExternalData(DownloadItem* item) { |
| 63 item->SetExternalData(kKey, this); |
| 64 } |
| 65 |
| 66 virtual ~SavePageExternalData() {} |
| 67 |
| 68 private: |
| 69 static const char kKey[]; |
| 70 |
| 71 DISALLOW_COPY_AND_ASSIGN(SavePageExternalData); |
| 72 }; |
| 73 |
| 74 const char SavePageExternalData::kKey[] = "DownloadItem SavePageExternalData"; |
| 75 |
54 void BeginDownload(content::DownloadUrlParameters* params) { | 76 void BeginDownload(content::DownloadUrlParameters* params) { |
55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
56 // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and | 78 // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and |
57 // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so | 79 // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so |
58 // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4. | 80 // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4. |
59 scoped_ptr<net::URLRequest> request(new net::URLRequest( | 81 scoped_ptr<net::URLRequest> request(new net::URLRequest( |
60 params->url(), | 82 params->url(), |
61 NULL, | 83 NULL, |
62 params->resource_context()->GetRequestContext())); | 84 params->resource_context()->GetRequestContext())); |
63 request->set_referrer(params->referrer().url.spec()); | 85 request->set_referrer(params->referrer().url.spec()); |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 // in DownloadItem destruction. | 321 // in DownloadItem destruction. |
300 DownloadMap downloads_to_delete; | 322 DownloadMap downloads_to_delete; |
301 downloads_to_delete.swap(downloads_); | 323 downloads_to_delete.swap(downloads_); |
302 | 324 |
303 active_downloads_.clear(); | 325 active_downloads_.clear(); |
304 STLDeleteValues(&downloads_to_delete); | 326 STLDeleteValues(&downloads_to_delete); |
305 | 327 |
306 // We'll have nothing more to report to the observers after this point. | 328 // We'll have nothing more to report to the observers after this point. |
307 observers_.Clear(); | 329 observers_.Clear(); |
308 | 330 |
309 DCHECK(save_page_downloads_.empty()); | |
310 | |
311 file_manager_ = NULL; | 331 file_manager_ = NULL; |
312 if (delegate_) | 332 if (delegate_) |
313 delegate_->Shutdown(); | 333 delegate_->Shutdown(); |
314 } | 334 } |
315 | 335 |
316 void DownloadManagerImpl::GetTemporaryDownloads( | 336 void DownloadManagerImpl::GetTemporaryDownloads( |
317 const FilePath& dir_path, DownloadVector* result) { | 337 const FilePath& dir_path, DownloadVector* result) { |
318 DCHECK(result); | 338 DCHECK(result); |
319 | 339 |
320 for (DownloadMap::iterator it = downloads_.begin(); | 340 for (DownloadMap::iterator it = downloads_.begin(); |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 page_url, | 553 page_url, |
534 is_otr, | 554 is_otr, |
535 GetNextId(), | 555 GetNextId(), |
536 mime_type, | 556 mime_type, |
537 bound_net_log); | 557 bound_net_log); |
538 | 558 |
539 download->AddObserver(observer); | 559 download->AddObserver(observer); |
540 | 560 |
541 DCHECK(!ContainsKey(downloads_, download->GetId())); | 561 DCHECK(!ContainsKey(downloads_, download->GetId())); |
542 downloads_[download->GetId()] = download; | 562 downloads_[download->GetId()] = download; |
543 DCHECK(!ContainsKey(save_page_downloads_, download->GetId())); | 563 DCHECK(!SavePageExternalData::Get(download)); |
544 save_page_downloads_[download->GetId()] = download; | 564 new SavePageExternalData(download); |
| 565 DCHECK(SavePageExternalData::Get(download)); |
545 | 566 |
546 // Will notify the observer in the callback. | 567 // Will notify the observer in the callback. |
547 if (delegate_) | 568 if (delegate_) |
548 delegate_->AddItemToPersistentStore(download); | 569 delegate_->AddItemToPersistentStore(download); |
549 | 570 |
550 return download; | 571 return download; |
551 } | 572 } |
552 | 573 |
553 // The target path for the download item is now valid. We proceed with the | 574 // The target path for the download item is now valid. We proceed with the |
554 // determination of an intermediate path. | 575 // determination of an intermediate path. |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
797 const DownloadVector& pending_deletes) { | 818 const DownloadVector& pending_deletes) { |
798 if (pending_deletes.empty()) | 819 if (pending_deletes.empty()) |
799 return 0; | 820 return 0; |
800 | 821 |
801 // Delete from internal maps. | 822 // Delete from internal maps. |
802 for (DownloadVector::const_iterator it = pending_deletes.begin(); | 823 for (DownloadVector::const_iterator it = pending_deletes.begin(); |
803 it != pending_deletes.end(); | 824 it != pending_deletes.end(); |
804 ++it) { | 825 ++it) { |
805 DownloadItem* download = *it; | 826 DownloadItem* download = *it; |
806 DCHECK(download); | 827 DCHECK(download); |
807 save_page_downloads_.erase(download->GetId()); | |
808 downloads_.erase(download->GetId()); | 828 downloads_.erase(download->GetId()); |
809 } | 829 } |
810 | 830 |
811 // Tell observers to refresh their views. | 831 // Tell observers to refresh their views. |
812 NotifyModelChanged(); | 832 NotifyModelChanged(); |
813 | 833 |
814 // Delete the download items themselves. | 834 // Delete the download items themselves. |
815 const int num_deleted = static_cast<int>(pending_deletes.size()); | 835 const int num_deleted = static_cast<int>(pending_deletes.size()); |
816 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); | 836 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); |
817 return num_deleted; | 837 return num_deleted; |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 // This includes buttons to save or cancel, for a dangerous download. | 988 // This includes buttons to save or cancel, for a dangerous download. |
969 ShowDownloadInBrowser(download); | 989 ShowDownloadInBrowser(download); |
970 | 990 |
971 // Inform interested objects about the new download. | 991 // Inform interested objects about the new download. |
972 NotifyModelChanged(); | 992 NotifyModelChanged(); |
973 } | 993 } |
974 | 994 |
975 | 995 |
976 void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id, | 996 void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id, |
977 int64 db_handle) { | 997 int64 db_handle) { |
978 if (save_page_downloads_.count(download_id)) { | 998 DownloadItem* item = GetDownload(download_id); |
979 OnSavePageItemAddedToPersistentStore(download_id, db_handle); | 999 // It's valid that we don't find a matching item, i.e. on shutdown. |
980 } else if (active_downloads_.count(download_id)) { | 1000 if (!item) |
981 OnDownloadItemAddedToPersistentStore(download_id, db_handle); | 1001 return; |
| 1002 AddDownloadItemToHistory(item, db_handle); |
| 1003 if (SavePageExternalData::Get(item)) { |
| 1004 OnSavePageItemAddedToPersistentStore(item); |
| 1005 } else { |
| 1006 OnDownloadItemAddedToPersistentStore(item); |
982 } | 1007 } |
983 // It's valid that we don't find a matching item, i.e. on shutdown. | |
984 } | 1008 } |
985 | 1009 |
986 // Once the new DownloadItem has been committed to the persistent store, | 1010 // Once the new DownloadItem has been committed to the persistent store, |
987 // associate it with its db_handle (TODO(benjhayden) merge db_handle with id), | 1011 // associate it with its db_handle (TODO(benjhayden) merge db_handle with id), |
988 // show it in the browser (TODO(benjhayden) the ui should observe us instead), | 1012 // show it in the browser (TODO(benjhayden) the ui should observe us instead), |
989 // and notify observers (TODO(benjhayden) observers should be able to see the | 1013 // and notify observers (TODO(benjhayden) observers should be able to see the |
990 // item when it's created so they can observe it directly. Are there any | 1014 // item when it's created so they can observe it directly. Are there any |
991 // clients that actually need to know when the item is added to the history?). | 1015 // clients that actually need to know when the item is added to the history?). |
992 void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore( | 1016 void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore( |
993 int32 download_id, int64 db_handle) { | 1017 DownloadItem* item) { |
994 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1018 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
995 DownloadItem* download = GetActiveDownloadItem(download_id); | |
996 if (!download) | |
997 return; | |
998 | 1019 |
999 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle | 1020 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << item->GetDbHandle() |
1000 << " download_id = " << download_id | 1021 << " download_id = " << item->GetId() |
1001 << " download = " << download->DebugString(true); | 1022 << " download = " << item->DebugString(true); |
1002 | |
1003 AddDownloadItemToHistory(download, db_handle); | |
1004 | 1023 |
1005 // If the download is still in progress, try to complete it. | 1024 // If the download is still in progress, try to complete it. |
1006 // | 1025 // |
1007 // Otherwise, download has been cancelled or interrupted before we've | 1026 // Otherwise, download has been cancelled or interrupted before we've |
1008 // received the DB handle. We post one final message to the history | 1027 // received the DB handle. We post one final message to the history |
1009 // service so that it can be properly in sync with the DownloadItem's | 1028 // service so that it can be properly in sync with the DownloadItem's |
1010 // completion status, and also inform any observers so that they get | 1029 // completion status, and also inform any observers so that they get |
1011 // more than just the start notification. | 1030 // more than just the start notification. |
1012 if (download->IsInProgress()) { | 1031 if (item->IsInProgress()) { |
1013 MaybeCompleteDownload(download); | 1032 MaybeCompleteDownload(item); |
1014 } else { | 1033 } else { |
1015 DCHECK(download->IsCancelled()); | 1034 DCHECK(item->IsCancelled()); |
1016 active_downloads_.erase(download_id); | 1035 active_downloads_.erase(item->GetId()); |
1017 if (delegate_) | 1036 if (delegate_) |
1018 delegate_->UpdateItemInPersistentStore(download); | 1037 delegate_->UpdateItemInPersistentStore(item); |
1019 download->UpdateObservers(); | 1038 item->UpdateObservers(); |
1020 } | 1039 } |
1021 } | 1040 } |
1022 | 1041 |
1023 void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) { | 1042 void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) { |
1024 // The 'contents' may no longer exist if the user closed the contents before | 1043 // The 'contents' may no longer exist if the user closed the contents before |
1025 // we get this start completion event. | 1044 // we get this start completion event. |
1026 WebContents* content = download->GetWebContents(); | 1045 WebContents* content = download->GetWebContents(); |
1027 | 1046 |
1028 // If the contents no longer exists, we ask the embedder to suggest another | 1047 // If the contents no longer exists, we ask the embedder to suggest another |
1029 // contents. | 1048 // contents. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1070 if (ContainsKey(active_downloads_, download_id)) | 1089 if (ContainsKey(active_downloads_, download_id)) |
1071 return active_downloads_[download_id]; | 1090 return active_downloads_[download_id]; |
1072 return NULL; | 1091 return NULL; |
1073 } | 1092 } |
1074 | 1093 |
1075 // Confirm that everything in all maps is also in |downloads_|, and that | 1094 // Confirm that everything in all maps is also in |downloads_|, and that |
1076 // everything in |downloads_| is also in some other map. | 1095 // everything in |downloads_| is also in some other map. |
1077 void DownloadManagerImpl::AssertContainersConsistent() const { | 1096 void DownloadManagerImpl::AssertContainersConsistent() const { |
1078 #if !defined(NDEBUG) | 1097 #if !defined(NDEBUG) |
1079 // Turn everything into sets. | 1098 // Turn everything into sets. |
1080 const DownloadMap* input_maps[] = {&active_downloads_, | 1099 const DownloadMap* input_maps[] = {&active_downloads_}; |
1081 &save_page_downloads_}; | 1100 DownloadSet active_set; |
1082 DownloadSet active_set, save_page_set; | 1101 DownloadSet* all_sets[] = {&active_set}; |
1083 DownloadSet* all_sets[] = {&active_set, &save_page_set}; | |
1084 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets)); | 1102 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets)); |
1085 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { | 1103 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { |
1086 for (DownloadMap::const_iterator it = input_maps[i]->begin(); | 1104 for (DownloadMap::const_iterator it = input_maps[i]->begin(); |
1087 it != input_maps[i]->end(); ++it) { | 1105 it != input_maps[i]->end(); ++it) { |
1088 all_sets[i]->insert(&*it->second); | 1106 all_sets[i]->insert(&*it->second); |
1089 } | 1107 } |
1090 } | 1108 } |
1091 | 1109 |
1092 DownloadSet all_downloads; | 1110 DownloadSet all_downloads; |
1093 for (DownloadMap::const_iterator it = downloads_.begin(); | 1111 for (DownloadMap::const_iterator it = downloads_.begin(); |
(...skipping 21 matching lines...) Expand all Loading... |
1115 // events complete. | 1133 // events complete. |
1116 // If something removes the download item from the download manager (Remove, | 1134 // If something removes the download item from the download manager (Remove, |
1117 // Shutdown) the result will be that the SavePage system will not be able to | 1135 // Shutdown) the result will be that the SavePage system will not be able to |
1118 // properly update the download item (which no longer exists) or the download | 1136 // properly update the download item (which no longer exists) or the download |
1119 // history, but the action will complete properly anyway. This may lead to the | 1137 // history, but the action will complete properly anyway. This may lead to the |
1120 // history entry being wrong on a reload of chrome (specifically in the case of | 1138 // history entry being wrong on a reload of chrome (specifically in the case of |
1121 // Initiation -> History Callback -> Removal -> Completion), but there's no way | 1139 // Initiation -> History Callback -> Removal -> Completion), but there's no way |
1122 // to solve that without canceling on Remove (which would then update the DB). | 1140 // to solve that without canceling on Remove (which would then update the DB). |
1123 | 1141 |
1124 void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore( | 1142 void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore( |
1125 int32 download_id, int64 db_handle) { | 1143 DownloadItem* item) { |
1126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1127 | 1145 |
1128 DownloadMap::const_iterator it = save_page_downloads_.find(download_id); | |
1129 // This can happen if the download manager is shutting down and all maps | |
1130 // have been cleared. | |
1131 if (it == save_page_downloads_.end()) | |
1132 return; | |
1133 | |
1134 DownloadItem* download = it->second; | |
1135 if (!download) { | |
1136 NOTREACHED(); | |
1137 return; | |
1138 } | |
1139 | |
1140 AddDownloadItemToHistory(download, db_handle); | |
1141 | |
1142 // Finalize this download if it finished before the history callback. | 1146 // Finalize this download if it finished before the history callback. |
1143 if (!download->IsInProgress()) | 1147 if (!item->IsInProgress()) |
1144 SavePageDownloadFinished(download); | 1148 SavePageDownloadFinished(item); |
1145 } | 1149 } |
1146 | 1150 |
1147 void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) { | 1151 void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) { |
1148 if (download->IsPersisted()) { | 1152 if (download->IsPersisted()) { |
1149 if (delegate_) | 1153 if (delegate_) |
1150 delegate_->UpdateItemInPersistentStore(download); | 1154 delegate_->UpdateItemInPersistentStore(download); |
1151 DCHECK(ContainsKey(save_page_downloads_, download->GetId())); | |
1152 save_page_downloads_.erase(download->GetId()); | |
1153 | |
1154 if (download->IsComplete()) | 1155 if (download->IsComplete()) |
1155 content::NotificationService::current()->Notify( | 1156 content::NotificationService::current()->Notify( |
1156 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, | 1157 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
1157 content::Source<DownloadManager>(this), | 1158 content::Source<DownloadManager>(this), |
1158 content::Details<DownloadItem>(download)); | 1159 content::Details<DownloadItem>(download)); |
1159 } | 1160 } |
1160 } | 1161 } |
1161 | 1162 |
1162 void DownloadManagerImpl::DownloadOpened(DownloadItem* download) { | 1163 void DownloadManagerImpl::DownloadOpened(DownloadItem* download) { |
1163 if (delegate_) | 1164 if (delegate_) |
(...skipping 21 matching lines...) Expand all Loading... |
1185 void DownloadManagerImpl::DownloadRenamedToFinalName( | 1186 void DownloadManagerImpl::DownloadRenamedToFinalName( |
1186 DownloadItem* download) { | 1187 DownloadItem* download) { |
1187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1188 // If the rename failed, we receive an OnDownloadInterrupted() call before we | 1189 // If the rename failed, we receive an OnDownloadInterrupted() call before we |
1189 // receive the DownloadRenamedToFinalName() call. | 1190 // receive the DownloadRenamedToFinalName() call. |
1190 if (delegate_) { | 1191 if (delegate_) { |
1191 delegate_->UpdatePathForItemInPersistentStore( | 1192 delegate_->UpdatePathForItemInPersistentStore( |
1192 download, download->GetFullPath()); | 1193 download, download->GetFullPath()); |
1193 } | 1194 } |
1194 } | 1195 } |
OLD | NEW |