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 "chrome/browser/download/download_manager.h" | 5 #include "chrome/browser/download/download_manager.h" |
6 | 6 |
7 #include "base/callback.h" | 7 #include "base/callback.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/i18n/case_conversion.h" | 9 #include "base/i18n/case_conversion.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 #include "chrome/browser/tab_contents/tab_util.h" | 33 #include "chrome/browser/tab_contents/tab_util.h" |
34 #include "chrome/common/chrome_paths.h" | 34 #include "chrome/common/chrome_paths.h" |
35 #include "chrome/common/pref_names.h" | 35 #include "chrome/common/pref_names.h" |
36 #include "content/browser/browser_thread.h" | 36 #include "content/browser/browser_thread.h" |
37 #include "content/browser/content_browser_client.h" | 37 #include "content/browser/content_browser_client.h" |
38 #include "content/browser/renderer_host/render_process_host.h" | 38 #include "content/browser/renderer_host/render_process_host.h" |
39 #include "content/browser/renderer_host/render_view_host.h" | 39 #include "content/browser/renderer_host/render_view_host.h" |
40 #include "content/browser/renderer_host/resource_dispatcher_host.h" | 40 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
41 #include "content/browser/tab_contents/tab_contents.h" | 41 #include "content/browser/tab_contents/tab_contents.h" |
42 #include "content/common/content_notification_types.h" | 42 #include "content/common/content_notification_types.h" |
| 43 #include "content/common/notification_service.h" |
43 #include "googleurl/src/gurl.h" | 44 #include "googleurl/src/gurl.h" |
44 #include "grit/generated_resources.h" | 45 #include "grit/generated_resources.h" |
45 #include "grit/theme_resources.h" | 46 #include "grit/theme_resources.h" |
46 #include "net/base/mime_util.h" | 47 #include "net/base/mime_util.h" |
47 #include "net/base/net_util.h" | 48 #include "net/base/net_util.h" |
48 #include "ui/base/l10n/l10n_util.h" | 49 #include "ui/base/l10n/l10n_util.h" |
49 #include "ui/base/resource/resource_bundle.h" | 50 #include "ui/base/resource/resource_bundle.h" |
50 | 51 |
51 DownloadManager::DownloadManager(DownloadStatusUpdater* status_updater) | 52 DownloadManager::DownloadManager(DownloadStatusUpdater* status_updater) |
52 : shutdown_needed_(false), | 53 : shutdown_needed_(false), |
53 profile_(NULL), | 54 profile_(NULL), |
54 file_manager_(NULL), | 55 file_manager_(NULL), |
55 status_updater_(status_updater->AsWeakPtr()) { | 56 status_updater_(status_updater->AsWeakPtr()), |
| 57 next_save_page_id_(0) { |
56 if (status_updater_) | 58 if (status_updater_) |
57 status_updater_->AddDelegate(this); | 59 status_updater_->AddDelegate(this); |
58 } | 60 } |
59 | 61 |
60 DownloadManager::~DownloadManager() { | 62 DownloadManager::~DownloadManager() { |
61 DCHECK(!shutdown_needed_); | 63 DCHECK(!shutdown_needed_); |
62 if (status_updater_) | 64 if (status_updater_) |
63 status_updater_->RemoveDelegate(this); | 65 status_updater_->RemoveDelegate(this); |
64 } | 66 } |
65 | 67 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 // anything left. | 115 // anything left. |
114 | 116 |
115 // Copy downloads_ to separate container so as not to set off checks | 117 // Copy downloads_ to separate container so as not to set off checks |
116 // in DownloadItem destruction. | 118 // in DownloadItem destruction. |
117 DownloadSet downloads_to_delete; | 119 DownloadSet downloads_to_delete; |
118 downloads_to_delete.swap(downloads_); | 120 downloads_to_delete.swap(downloads_); |
119 | 121 |
120 in_progress_.clear(); | 122 in_progress_.clear(); |
121 active_downloads_.clear(); | 123 active_downloads_.clear(); |
122 history_downloads_.clear(); | 124 history_downloads_.clear(); |
123 #if !defined(NDEBUG) | |
124 save_page_as_downloads_.clear(); | |
125 #endif | |
126 STLDeleteElements(&downloads_to_delete); | 125 STLDeleteElements(&downloads_to_delete); |
127 | 126 |
| 127 DCHECK(save_page_downloads_.empty()); |
| 128 |
128 file_manager_ = NULL; | 129 file_manager_ = NULL; |
129 | 130 |
130 download_history_.reset(); | 131 download_history_.reset(); |
131 download_prefs_.reset(); | 132 download_prefs_.reset(); |
132 | 133 |
133 shutdown_needed_ = false; | 134 shutdown_needed_ = false; |
134 } | 135 } |
135 | 136 |
136 void DownloadManager::GetTemporaryDownloads( | 137 void DownloadManager::GetTemporaryDownloads( |
137 const FilePath& dir_path, std::vector<DownloadItem*>* result) { | 138 const FilePath& dir_path, DownloadVector* result) { |
138 DCHECK(result); | 139 DCHECK(result); |
139 | 140 |
140 for (DownloadMap::iterator it = history_downloads_.begin(); | 141 for (DownloadMap::iterator it = history_downloads_.begin(); |
141 it != history_downloads_.end(); ++it) { | 142 it != history_downloads_.end(); ++it) { |
142 if (it->second->is_temporary() && | 143 if (it->second->is_temporary() && |
143 it->second->full_path().DirName() == dir_path) | 144 it->second->full_path().DirName() == dir_path) |
144 result->push_back(it->second); | 145 result->push_back(it->second); |
145 } | 146 } |
146 } | 147 } |
147 | 148 |
148 void DownloadManager::GetAllDownloads( | 149 void DownloadManager::GetAllDownloads( |
149 const FilePath& dir_path, std::vector<DownloadItem*>* result) { | 150 const FilePath& dir_path, DownloadVector* result) { |
150 DCHECK(result); | 151 DCHECK(result); |
151 | 152 |
152 for (DownloadMap::iterator it = history_downloads_.begin(); | 153 for (DownloadMap::iterator it = history_downloads_.begin(); |
153 it != history_downloads_.end(); ++it) { | 154 it != history_downloads_.end(); ++it) { |
154 if (!it->second->is_temporary() && | 155 if (!it->second->is_temporary() && |
155 (dir_path.empty() || it->second->full_path().DirName() == dir_path)) | 156 (dir_path.empty() || it->second->full_path().DirName() == dir_path)) |
156 result->push_back(it->second); | 157 result->push_back(it->second); |
157 } | 158 } |
158 } | 159 } |
159 | 160 |
160 void DownloadManager::GetCurrentDownloads( | 161 void DownloadManager::GetCurrentDownloads( |
161 const FilePath& dir_path, std::vector<DownloadItem*>* result) { | 162 const FilePath& dir_path, DownloadVector* result) { |
162 DCHECK(result); | 163 DCHECK(result); |
163 | 164 |
164 for (DownloadMap::iterator it = history_downloads_.begin(); | 165 for (DownloadMap::iterator it = history_downloads_.begin(); |
165 it != history_downloads_.end(); ++it) { | 166 it != history_downloads_.end(); ++it) { |
166 DownloadItem* item =it->second; | 167 DownloadItem* item =it->second; |
167 // Skip temporary items. | 168 // Skip temporary items. |
168 if (item->is_temporary()) | 169 if (item->is_temporary()) |
169 continue; | 170 continue; |
170 // Skip items that have all their data, and are OK to save. | 171 // Skip items that have all their data, and are OK to save. |
171 if (!item->IsPartialDownload() && | 172 if (!item->IsPartialDownload() && |
172 (item->safety_state() != DownloadItem::DANGEROUS)) | 173 (item->safety_state() != DownloadItem::DANGEROUS)) |
173 continue; | 174 continue; |
174 // Skip items that don't match |dir_path|. | 175 // Skip items that don't match |dir_path|. |
175 // If |dir_path| is empty, all remaining items match. | 176 // If |dir_path| is empty, all remaining items match. |
176 if (!dir_path.empty() && (it->second->full_path().DirName() != dir_path)) | 177 if (!dir_path.empty() && (it->second->full_path().DirName() != dir_path)) |
177 continue; | 178 continue; |
178 | 179 |
179 result->push_back(item); | 180 result->push_back(item); |
180 } | 181 } |
181 | 182 |
182 // If we have a parent profile, let it add its downloads to the results. | 183 // If we have a parent profile, let it add its downloads to the results. |
183 Profile* original_profile = profile_->GetOriginalProfile(); | 184 Profile* original_profile = profile_->GetOriginalProfile(); |
184 if (original_profile != profile_) | 185 if (original_profile != profile_) |
185 original_profile->GetDownloadManager()->GetCurrentDownloads(dir_path, | 186 original_profile->GetDownloadManager()->GetCurrentDownloads(dir_path, |
186 result); | 187 result); |
187 } | 188 } |
188 | 189 |
189 void DownloadManager::SearchDownloads(const string16& query, | 190 void DownloadManager::SearchDownloads(const string16& query, |
190 std::vector<DownloadItem*>* result) { | 191 DownloadVector* result) { |
191 DCHECK(result); | 192 DCHECK(result); |
192 | 193 |
193 string16 query_lower(base::i18n::ToLower(query)); | 194 string16 query_lower(base::i18n::ToLower(query)); |
194 | 195 |
195 for (DownloadMap::iterator it = history_downloads_.begin(); | 196 for (DownloadMap::iterator it = history_downloads_.begin(); |
196 it != history_downloads_.end(); ++it) { | 197 it != history_downloads_.end(); ++it) { |
197 DownloadItem* download_item = it->second; | 198 DownloadItem* download_item = it->second; |
198 | 199 |
199 if (download_item->is_temporary() || download_item->is_extension_install()) | 200 if (download_item->is_temporary() || download_item->is_extension_install()) |
200 continue; | 201 continue; |
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
868 BrowserThread::FILE, FROM_HERE, | 869 BrowserThread::FILE, FROM_HERE, |
869 NewRunnableMethod( | 870 NewRunnableMethod( |
870 file_manager_, &DownloadFileManager::CancelDownload, download_id)); | 871 file_manager_, &DownloadFileManager::CancelDownload, download_id)); |
871 } | 872 } |
872 | 873 |
873 void DownloadManager::UpdateAppIcon() { | 874 void DownloadManager::UpdateAppIcon() { |
874 if (status_updater_) | 875 if (status_updater_) |
875 status_updater_->Update(); | 876 status_updater_->Update(); |
876 } | 877 } |
877 | 878 |
| 879 int DownloadManager::RemoveDownloadItems( |
| 880 const DownloadVector& pending_deletes) { |
| 881 if (pending_deletes.empty()) |
| 882 return 0; |
| 883 |
| 884 // Delete from internal maps. |
| 885 for (DownloadVector::const_iterator it = pending_deletes.begin(); |
| 886 it != pending_deletes.end(); |
| 887 ++it) { |
| 888 DownloadItem* download = *it; |
| 889 DCHECK(download); |
| 890 history_downloads_.erase(download->db_handle()); |
| 891 save_page_downloads_.erase(download->id()); |
| 892 downloads_.erase(download); |
| 893 } |
| 894 |
| 895 // Tell observers to refresh their views. |
| 896 NotifyModelChanged(); |
| 897 |
| 898 // Delete the download items themselves. |
| 899 const int num_deleted = static_cast<int>(pending_deletes.size()); |
| 900 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); |
| 901 return num_deleted; |
| 902 } |
| 903 |
878 void DownloadManager::RemoveDownload(int64 download_handle) { | 904 void DownloadManager::RemoveDownload(int64 download_handle) { |
879 DownloadMap::iterator it = history_downloads_.find(download_handle); | 905 DownloadMap::iterator it = history_downloads_.find(download_handle); |
880 if (it == history_downloads_.end()) | 906 if (it == history_downloads_.end()) |
881 return; | 907 return; |
882 | 908 |
883 // Make history update. | 909 // Make history update. |
884 DownloadItem* download = it->second; | 910 DownloadItem* download = it->second; |
885 download_history_->RemoveEntry(download); | 911 download_history_->RemoveEntry(download); |
886 | 912 |
887 // Remove from our tables and delete. | 913 // Remove from our tables and delete. |
888 history_downloads_.erase(it); | 914 int downloads_count = RemoveDownloadItems(DownloadVector(1, download)); |
889 int downloads_count = downloads_.erase(download); | |
890 DCHECK_EQ(1, downloads_count); | 915 DCHECK_EQ(1, downloads_count); |
891 | |
892 // Tell observers to refresh their views. | |
893 NotifyModelChanged(); | |
894 | |
895 delete download; | |
896 } | 916 } |
897 | 917 |
898 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, | 918 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, |
899 const base::Time remove_end) { | 919 const base::Time remove_end) { |
900 download_history_->RemoveEntriesBetween(remove_begin, remove_end); | 920 download_history_->RemoveEntriesBetween(remove_begin, remove_end); |
901 | 921 |
902 // All downloads visible to the user will be in the history, | 922 // All downloads visible to the user will be in the history, |
903 // so scan that map. | 923 // so scan that map. |
904 DownloadMap::iterator it = history_downloads_.begin(); | 924 DownloadVector pending_deletes; |
905 std::vector<DownloadItem*> pending_deletes; | 925 for (DownloadMap::const_iterator it = history_downloads_.begin(); |
906 while (it != history_downloads_.end()) { | 926 it != history_downloads_.end(); |
| 927 ++it) { |
907 DownloadItem* download = it->second; | 928 DownloadItem* download = it->second; |
908 if (download->start_time() >= remove_begin && | 929 if (download->start_time() >= remove_begin && |
909 (remove_end.is_null() || download->start_time() < remove_end) && | 930 (remove_end.is_null() || download->start_time() < remove_end) && |
910 (download->IsComplete() || | 931 (download->IsComplete() || download->IsCancelled())) { |
911 download->IsCancelled() || | |
912 download->IsInterrupted())) { | |
913 AssertQueueStateConsistent(download); | 932 AssertQueueStateConsistent(download); |
914 | |
915 // Remove from the map and move to the next in the list. | |
916 history_downloads_.erase(it++); | |
917 | |
918 // Also remove it from any completed dangerous downloads. | |
919 pending_deletes.push_back(download); | 933 pending_deletes.push_back(download); |
920 | |
921 continue; | |
922 } | 934 } |
923 | |
924 ++it; | |
925 } | 935 } |
926 | 936 return RemoveDownloadItems(pending_deletes); |
927 // If we aren't deleting anything, we're done. | |
928 if (pending_deletes.empty()) | |
929 return 0; | |
930 | |
931 // Remove the chosen downloads from the main owning container. | |
932 for (std::vector<DownloadItem*>::iterator it = pending_deletes.begin(); | |
933 it != pending_deletes.end(); it++) { | |
934 downloads_.erase(*it); | |
935 } | |
936 | |
937 // Tell observers to refresh their views. | |
938 NotifyModelChanged(); | |
939 | |
940 // Delete the download items themselves. | |
941 int num_deleted = static_cast<int>(pending_deletes.size()); | |
942 | |
943 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); | |
944 pending_deletes.clear(); | |
945 | |
946 return num_deleted; | |
947 } | 937 } |
948 | 938 |
949 int DownloadManager::RemoveDownloads(const base::Time remove_begin) { | 939 int DownloadManager::RemoveDownloads(const base::Time remove_begin) { |
950 return RemoveDownloadsBetween(remove_begin, base::Time()); | 940 return RemoveDownloadsBetween(remove_begin, base::Time()); |
951 } | 941 } |
952 | 942 |
953 int DownloadManager::RemoveAllDownloads() { | 943 int DownloadManager::RemoveAllDownloads() { |
954 if (this != profile_->GetOriginalProfile()->GetDownloadManager()) { | 944 if (this != profile_->GetOriginalProfile()->GetDownloadManager()) { |
955 // This is an incognito downloader. Clear All should clear main download | 945 // This is an incognito downloader. Clear All should clear main download |
956 // manager as well. | 946 // manager as well. |
957 profile_->GetOriginalProfile()->GetDownloadManager()->RemoveAllDownloads(); | 947 profile_->GetOriginalProfile()->GetDownloadManager()->RemoveAllDownloads(); |
958 } | 948 } |
959 // The null times make the date range unbounded. | 949 // The null times make the date range unbounded. |
960 return RemoveDownloadsBetween(base::Time(), base::Time()); | 950 return RemoveDownloadsBetween(base::Time(), base::Time()); |
961 } | 951 } |
962 | 952 |
963 void DownloadManager::SavePageAsDownloadStarted(DownloadItem* download) { | |
964 #if !defined(NDEBUG) | |
965 save_page_as_downloads_.insert(download); | |
966 #endif | |
967 downloads_.insert(download); | |
968 // Add to history and notify observers. | |
969 AddDownloadItemToHistory(download, DownloadHistory::kUninitializedHandle); | |
970 NotifyModelChanged(); | |
971 } | |
972 | |
973 // Initiate a download of a specific URL. We send the request to the | 953 // Initiate a download of a specific URL. We send the request to the |
974 // ResourceDispatcherHost, and let it send us responses like a regular | 954 // ResourceDispatcherHost, and let it send us responses like a regular |
975 // download. | 955 // download. |
976 void DownloadManager::DownloadUrl(const GURL& url, | 956 void DownloadManager::DownloadUrl(const GURL& url, |
977 const GURL& referrer, | 957 const GURL& referrer, |
978 const std::string& referrer_charset, | 958 const std::string& referrer_charset, |
979 TabContents* tab_contents) { | 959 TabContents* tab_contents) { |
980 DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(), | 960 DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(), |
981 tab_contents); | 961 tab_contents); |
982 } | 962 } |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1156 | 1136 |
1157 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508 | 1137 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508 |
1158 // is fixed. | 1138 // is fixed. |
1159 CHECK_NE(DownloadHistory::kUninitializedHandle, db_handle); | 1139 CHECK_NE(DownloadHistory::kUninitializedHandle, db_handle); |
1160 | 1140 |
1161 DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle); | 1141 DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle); |
1162 download->set_db_handle(db_handle); | 1142 download->set_db_handle(db_handle); |
1163 | 1143 |
1164 DCHECK(!ContainsKey(history_downloads_, download->db_handle())); | 1144 DCHECK(!ContainsKey(history_downloads_, download->db_handle())); |
1165 history_downloads_[download->db_handle()] = download; | 1145 history_downloads_[download->db_handle()] = download; |
| 1146 |
| 1147 // Show in the appropriate browser UI. |
| 1148 // This includes buttons to save or cancel, for a dangerous download. |
| 1149 ShowDownloadInBrowser(download); |
| 1150 |
| 1151 // Inform interested objects about the new download. |
| 1152 NotifyModelChanged(); |
1166 } | 1153 } |
1167 | 1154 |
1168 // Once the new DownloadItem's creation info has been committed to the history | 1155 // Once the new DownloadItem's creation info has been committed to the history |
1169 // service, we associate the DownloadItem with the db handle, update our | 1156 // service, we associate the DownloadItem with the db handle, update our |
1170 // 'history_downloads_' map and inform observers. | 1157 // 'history_downloads_' map and inform observers. |
1171 void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id, | 1158 void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id, |
1172 int64 db_handle) { | 1159 int64 db_handle) { |
1173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1174 DownloadItem* download = GetActiveDownloadItem(download_id); | 1161 DownloadItem* download = GetActiveDownloadItem(download_id); |
1175 if (!download) | 1162 if (!download) |
1176 return; | 1163 return; |
1177 | 1164 |
1178 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle | 1165 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle |
1179 << " download_id = " << download_id | 1166 << " download_id = " << download_id |
1180 << " download = " << download->DebugString(true); | 1167 << " download = " << download->DebugString(true); |
1181 | 1168 |
1182 AddDownloadItemToHistory(download, db_handle); | 1169 AddDownloadItemToHistory(download, db_handle); |
1183 | 1170 |
1184 // Show in the appropriate browser UI. | |
1185 // This includes buttons to save or cancel, for a dangerous download. | |
1186 ShowDownloadInBrowser(download); | |
1187 | |
1188 // Inform interested objects about the new download. | |
1189 NotifyModelChanged(); | |
1190 | |
1191 // If the download is still in progress, try to complete it. | 1171 // If the download is still in progress, try to complete it. |
1192 // | 1172 // |
1193 // Otherwise, download has been cancelled or interrupted before we've | 1173 // Otherwise, download has been cancelled or interrupted before we've |
1194 // received the DB handle. We post one final message to the history | 1174 // received the DB handle. We post one final message to the history |
1195 // service so that it can be properly in sync with the DownloadItem's | 1175 // service so that it can be properly in sync with the DownloadItem's |
1196 // completion status, and also inform any observers so that they get | 1176 // completion status, and also inform any observers so that they get |
1197 // more than just the start notification. | 1177 // more than just the start notification. |
1198 if (download->IsInProgress()) { | 1178 if (download->IsInProgress()) { |
1199 MaybeCompleteDownload(download); | 1179 MaybeCompleteDownload(download); |
1200 } else { | 1180 } else { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1250 DownloadItem* download = active_downloads_[download_id]; | 1230 DownloadItem* download = active_downloads_[download_id]; |
1251 DCHECK(download != NULL); | 1231 DCHECK(download != NULL); |
1252 return download; | 1232 return download; |
1253 } | 1233 } |
1254 | 1234 |
1255 // Confirm that everything in all maps is also in |downloads_|, and that | 1235 // Confirm that everything in all maps is also in |downloads_|, and that |
1256 // everything in |downloads_| is also in some other map. | 1236 // everything in |downloads_| is also in some other map. |
1257 void DownloadManager::AssertContainersConsistent() const { | 1237 void DownloadManager::AssertContainersConsistent() const { |
1258 #if !defined(NDEBUG) | 1238 #if !defined(NDEBUG) |
1259 // Turn everything into sets. | 1239 // Turn everything into sets. |
1260 DownloadSet active_set, history_set; | 1240 const DownloadMap* input_maps[] = {&active_downloads_, |
1261 const DownloadMap* input_maps[] = {&active_downloads_, &history_downloads_}; | 1241 &history_downloads_, |
1262 DownloadSet* local_sets[] = {&active_set, &history_set}; | 1242 &save_page_downloads_}; |
1263 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(local_sets)); | 1243 DownloadSet active_set, history_set, save_page_set; |
| 1244 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set}; |
| 1245 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets)); |
1264 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { | 1246 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { |
1265 for (DownloadMap::const_iterator it = input_maps[i]->begin(); | 1247 for (DownloadMap::const_iterator it = input_maps[i]->begin(); |
1266 it != input_maps[i]->end(); it++) { | 1248 it != input_maps[i]->end(); ++it) { |
1267 local_sets[i]->insert(&*it->second); | 1249 all_sets[i]->insert(&*it->second); |
1268 } | 1250 } |
1269 } | 1251 } |
1270 | 1252 |
1271 // Check if each set is fully present in downloads, and create a union. | 1253 // Check if each set is fully present in downloads, and create a union. |
1272 const DownloadSet* all_sets[] = {&active_set, &history_set, | |
1273 &save_page_as_downloads_}; | |
1274 DownloadSet downloads_union; | 1254 DownloadSet downloads_union; |
1275 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) { | 1255 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) { |
1276 DownloadSet remainder; | 1256 DownloadSet remainder; |
1277 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin()); | 1257 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin()); |
1278 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(), | 1258 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(), |
1279 downloads_.begin(), downloads_.end(), | 1259 downloads_.begin(), downloads_.end(), |
1280 insert_it); | 1260 insert_it); |
1281 DCHECK(remainder.empty()); | 1261 DCHECK(remainder.empty()); |
1282 std::insert_iterator<DownloadSet> | 1262 std::insert_iterator<DownloadSet> |
1283 insert_union(downloads_union, downloads_union.end()); | 1263 insert_union(downloads_union, downloads_union.end()); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1318 observed_download_manager_->RemoveObserver(this); | 1298 observed_download_manager_->RemoveObserver(this); |
1319 } | 1299 } |
1320 | 1300 |
1321 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { | 1301 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { |
1322 observing_download_manager_->NotifyModelChanged(); | 1302 observing_download_manager_->NotifyModelChanged(); |
1323 } | 1303 } |
1324 | 1304 |
1325 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { | 1305 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { |
1326 observed_download_manager_ = NULL; | 1306 observed_download_manager_ = NULL; |
1327 } | 1307 } |
| 1308 |
| 1309 void DownloadManager::SavePageDownloadStarted(DownloadItem* download) { |
| 1310 DCHECK(!ContainsKey(save_page_downloads_, download->id())); |
| 1311 downloads_.insert(download); |
| 1312 save_page_downloads_[download->id()] = download; |
| 1313 |
| 1314 // Add this entry to the history service. |
| 1315 // Additionally, the UI is notified in the callback. |
| 1316 download_history_->AddEntry(download, |
| 1317 NewCallback(this, &DownloadManager::OnSavePageDownloadEntryAdded)); |
| 1318 } |
| 1319 |
| 1320 // SavePackage will call SavePageDownloadFinished upon completion/cancellation. |
| 1321 // The history callback will call OnSavePageDownloadEntryAdded. |
| 1322 // If the download finishes before the history callback, |
| 1323 // OnSavePageDownloadEntryAdded calls SavePageDownloadFinished, ensuring that |
| 1324 // the history event is update regardless of the order in which these two events |
| 1325 // complete. |
| 1326 // If something removes the download item from the download manager (Remove, |
| 1327 // Shutdown) the result will be that the SavePage system will not be able to |
| 1328 // properly update the download item (which no longer exists) or the download |
| 1329 // history, but the action will complete properly anyway. This may lead to the |
| 1330 // history entry being wrong on a reload of chrome (specifically in the case of |
| 1331 // Initiation -> History Callback -> Removal -> Completion), but there's no way |
| 1332 // to solve that without canceling on Remove (which would then update the DB). |
| 1333 |
| 1334 void DownloadManager::OnSavePageDownloadEntryAdded(int32 download_id, |
| 1335 int64 db_handle) { |
| 1336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1337 |
| 1338 DownloadMap::const_iterator it = save_page_downloads_.find(download_id); |
| 1339 // This can happen if the download manager is shutting down and all maps |
| 1340 // have been cleared. |
| 1341 if (it == save_page_downloads_.end()) |
| 1342 return; |
| 1343 |
| 1344 DownloadItem* download = it->second; |
| 1345 if (!download) { |
| 1346 NOTREACHED(); |
| 1347 return; |
| 1348 } |
| 1349 |
| 1350 AddDownloadItemToHistory(download, db_handle); |
| 1351 |
| 1352 // Finalize this download if it finished before the history callback. |
| 1353 if (!download->IsInProgress()) |
| 1354 SavePageDownloadFinished(download); |
| 1355 } |
| 1356 |
| 1357 void DownloadManager::SavePageDownloadFinished(DownloadItem* download) { |
| 1358 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { |
| 1359 download_history_->UpdateEntry(download); |
| 1360 DCHECK(ContainsKey(save_page_downloads_, download->id())); |
| 1361 save_page_downloads_.erase(download->id()); |
| 1362 |
| 1363 if (download->IsComplete()) |
| 1364 NotificationService::current()->Notify( |
| 1365 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
| 1366 Source<DownloadManager>(this), |
| 1367 Details<DownloadItem>(download)); |
| 1368 } |
| 1369 } |
| 1370 |
| 1371 int32 DownloadManager::GetNextSavePageId() { |
| 1372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1373 return next_save_page_id_++; |
| 1374 } |
| 1375 |
OLD | NEW |