blob: 2276afc64be0ecfdcd358385b325de52918c0bbb [file] [log] [blame]
[email protected]0afff032012-01-06 20:55:001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]5656f8a2011-11-17 16:12:585#include "content/browser/download/download_manager_impl.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]e7557f172011-08-19 23:42:017#include <iterator>
8
[email protected]eda58402011-09-21 19:32:029#include "base/bind.h"
[email protected]2041cf342010-02-19 03:15:5910#include "base/callback.h"
[email protected]c6944272012-01-06 22:12:2811#include "base/debug/alias.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/file_util.h"
[email protected]503d03872011-05-06 08:36:2613#include "base/i18n/case_conversion.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/logging.h"
[email protected]7286e3fc2011-07-19 22:13:2415#include "base/stl_util.h"
[email protected]eda58402011-09-21 19:32:0216#include "base/stringprintf.h"
17#include "base/synchronization/lock.h"
18#include "base/sys_string_conversions.h"
[email protected]d2a8fb72010-01-21 05:31:4219#include "build/build_config.h"
[email protected]71bf3f5e2011-08-15 21:05:2220#include "content/browser/download/download_create_info.h"
21#include "content/browser/download/download_file_manager.h"
[email protected]c09a8fd2011-11-21 19:54:5022#include "content/browser/download/download_item_impl.h"
[email protected]bb1a4212011-08-22 22:38:2523#include "content/browser/download/download_persistent_store_info.h"
[email protected]da4a5582011-10-17 19:08:0624#include "content/browser/download/download_stats.h"
[email protected]71bf3f5e2011-08-15 21:05:2225#include "content/browser/download/download_status_updater.h"
[email protected]be76b7e2011-10-13 12:57:5726#include "content/browser/download/interrupt_reasons.h"
[email protected]7324d1d2011-03-01 05:02:1627#include "content/browser/renderer_host/render_view_host.h"
28#include "content/browser/renderer_host/resource_dispatcher_host.h"
29#include "content/browser/tab_contents/tab_contents.h"
[email protected]ccb797302011-12-15 16:55:1130#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4931#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4432#include "content/public/browser/content_browser_client.h"
[email protected]1bd0ef12011-10-20 05:24:1733#include "content/public/browser/download_manager_delegate.h"
[email protected]33d22102012-01-25 17:46:5334#include "content/public/browser/download_query.h"
[email protected]ad50def52011-10-19 23:17:0735#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1636#include "content/public/browser/notification_types.h"
[email protected]f3b1a082011-11-18 00:34:3037#include "content/public/browser/render_process_host.h"
[email protected]0bfbf882011-12-22 18:19:2738#include "content/public/browser/web_contents_delegate.h"
initial.commit09911bf2008-07-26 23:55:2939
[email protected]a896ce32012-01-09 22:04:0740// TODO(benjhayden): Change this to DCHECK when we have more debugging
41// information from the next dev cycle, before the next stable/beta branch is
42// cut, in order to prevent unnecessary crashes on those channels. If we still
43// don't have root cause before the dev cycle after the next stable/beta
44// releases, uncomment it out to re-enable debugging checks. Whenever this macro
45// is toggled, the corresponding macro in download_database.cc should also
46// be toggled. When 96627 is fixed, this macro and all its usages can be
47// deleted or permanently changed to DCHECK as appropriate.
48#define CHECK_96627 CHECK
49
[email protected]631bb742011-11-02 11:29:3950using content::BrowserThread;
[email protected]98e814062012-01-27 00:35:4251using content::DownloadId;
[email protected]e582fdd2011-12-20 16:48:1752using content::DownloadItem;
[email protected]2a6bc3e2011-12-28 23:51:3353using content::WebContents;
[email protected]631bb742011-11-02 11:29:3954
[email protected]a0ce3282011-08-19 20:49:5255namespace {
56
[email protected]fabf36d22011-10-28 21:50:1757// Param structs exist because base::Bind can only handle 6 args.
58struct URLParams {
59 URLParams(const GURL& url, const GURL& referrer)
60 : url_(url), referrer_(referrer) {}
61 GURL url_;
62 GURL referrer_;
63};
64
65struct RenderParams {
66 RenderParams(int rpi, int rvi)
67 : render_process_id_(rpi), render_view_id_(rvi) {}
68 int render_process_id_;
69 int render_view_id_;
70};
71
72void BeginDownload(const URLParams& url_params,
73 const DownloadSaveInfo& save_info,
74 ResourceDispatcherHost* resource_dispatcher_host,
75 const RenderParams& render_params,
76 const content::ResourceContext* context) {
[email protected]c1ba99842012-01-19 20:56:0577 scoped_ptr<net::URLRequest> request(
78 new net::URLRequest(url_params.url_, resource_dispatcher_host));
[email protected]fabf36d22011-10-28 21:50:1779 request->set_referrer(url_params.referrer_.spec());
[email protected]c79a0c02011-08-22 22:37:3780 resource_dispatcher_host->BeginDownload(
[email protected]c1ba99842012-01-19 20:56:0581 request.Pass(), save_info, true,
[email protected]8e3ae68c2011-09-16 22:15:4782 DownloadResourceHandler::OnStartedCallback(),
[email protected]fabf36d22011-10-28 21:50:1783 render_params.render_process_id_,
84 render_params.render_view_id_,
[email protected]c79a0c02011-08-22 22:37:3785 *context);
[email protected]a0ce3282011-08-19 20:49:5286}
87
[email protected]33d22102012-01-25 17:46:5388class MapValueIteratorAdapter {
89 public:
90 explicit MapValueIteratorAdapter(
91 base::hash_map<int64, DownloadItem*>::const_iterator iter)
92 : iter_(iter) {
93 }
94 ~MapValueIteratorAdapter() {}
95
96 DownloadItem* operator*() { return iter_->second; }
97
98 MapValueIteratorAdapter& operator++() {
99 ++iter_;
100 return *this;
101 }
102
103 bool operator!=(const MapValueIteratorAdapter& that) const {
104 return iter_ != that.iter_;
105 }
106
107 private:
108 base::hash_map<int64, DownloadItem*>::const_iterator iter_;
109 // Allow copy and assign.
110};
111
[email protected]a0ce3282011-08-19 20:49:52112} // namespace
113
[email protected]99907362012-01-11 05:41:40114namespace content {
115
116// static
117DownloadManager* DownloadManager::Create(
118 content::DownloadManagerDelegate* delegate,
[email protected]99907362012-01-11 05:41:40119 DownloadStatusUpdater* status_updater) {
[email protected]98e814062012-01-27 00:35:42120 return new DownloadManagerImpl(delegate, status_updater);
[email protected]99907362012-01-11 05:41:40121}
122
123} // namespace content
124
[email protected]5656f8a2011-11-17 16:12:58125DownloadManagerImpl::DownloadManagerImpl(
126 content::DownloadManagerDelegate* delegate,
[email protected]5656f8a2011-11-17 16:12:58127 DownloadStatusUpdater* status_updater)
128 : shutdown_needed_(false),
129 browser_context_(NULL),
130 file_manager_(NULL),
131 status_updater_((status_updater != NULL)
132 ? status_updater->AsWeakPtr()
133 : base::WeakPtr<DownloadStatusUpdater>()),
134 delegate_(delegate),
[email protected]5656f8a2011-11-17 16:12:58135 largest_db_handle_in_history_(DownloadItem::kUninitializedHandle) {
[email protected]eda58402011-09-21 19:32:02136 // NOTE(benjhayden): status_updater may be NULL when using
137 // TestingBrowserProcess.
138 if (status_updater_.get() != NULL)
[email protected]073ed7b2010-09-27 09:20:02139 status_updater_->AddDelegate(this);
initial.commit09911bf2008-07-26 23:55:29140}
141
[email protected]5656f8a2011-11-17 16:12:58142DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13143 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29144}
145
[email protected]5656f8a2011-11-17 16:12:58146DownloadId DownloadManagerImpl::GetNextId() {
[email protected]98e814062012-01-27 00:35:42147 return delegate_->GetNextId();
[email protected]2909e342011-10-29 00:46:53148}
149
[email protected]fc03de22011-12-06 23:28:12150bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
151 return delegate_->ShouldOpenDownload(item);
152}
153
154bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
155 return delegate_->ShouldOpenFileBasedOnExtension(path);
156}
157
[email protected]5656f8a2011-11-17 16:12:58158void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50159 VLOG(20) << __FUNCTION__ << "()"
160 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13161 if (!shutdown_needed_)
162 return;
163 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29164
[email protected]326a6a92010-09-10 20:21:13165 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown());
[email protected]fb4f8d902011-09-16 06:07:08166 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13167
168 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18169 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17170 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
171 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13172 }
initial.commit09911bf2008-07-26 23:55:29173
[email protected]f04182f32010-12-10 19:12:07174 AssertContainersConsistent();
175
176 // Go through all downloads in downloads_. Dangerous ones we need to
177 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09178 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07179 DownloadItem* download = *it;
180
181 // Save iterator from potential erases in this set done by called code.
182 // Iterators after an erasure point are still valid for lists and
183 // associative containers such as sets.
184 it++;
185
[email protected]c09a8fd2011-11-21 19:54:50186 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29187 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07188 // The user hasn't accepted it, so we need to remove it
189 // from the disk. This may or may not result in it being
190 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12191 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07192 // removes and deletes it if it's known to the history service)
193 // so the only thing we know after calling this function is that
194 // the download was deleted if-and-only-if it was removed
195 // from all queues.
[email protected]303077002011-04-19 23:21:01196 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26197 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17198 download->Cancel(false);
199 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29200 }
201 }
202
[email protected]f04182f32010-12-10 19:12:07203 // At this point, all dangerous downloads have had their files removed
204 // and all in progress downloads have been cancelled. We can now delete
205 // anything left.
[email protected]9ccbb372008-10-10 18:50:32206
[email protected]5cd11b6e2011-06-10 20:30:59207 // Copy downloads_ to separate container so as not to set off checks
208 // in DownloadItem destruction.
209 DownloadSet downloads_to_delete;
210 downloads_to_delete.swap(downloads_);
211
initial.commit09911bf2008-07-26 23:55:29212 in_progress_.clear();
[email protected]70850c72011-01-11 17:31:27213 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59214 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59215 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29216
[email protected]41f558fb2012-01-09 22:59:58217 // We'll have nothing more to report to the observers after this point.
218 observers_.Clear();
219
[email protected]6d0146c2011-08-04 19:13:04220 DCHECK(save_page_downloads_.empty());
221
initial.commit09911bf2008-07-26 23:55:29222 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53223 delegate_->Shutdown();
[email protected]82f37b02010-07-29 22:04:57224
[email protected]41f558fb2012-01-09 22:59:58225 if (status_updater_)
226 status_updater_->RemoveDelegate(this);
227 status_updater_.reset();
initial.commit09911bf2008-07-26 23:55:29228}
229
[email protected]5656f8a2011-11-17 16:12:58230void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04231 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57232 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58233
[email protected]f04182f32010-12-10 19:12:07234 for (DownloadMap::iterator it = history_downloads_.begin();
235 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50236 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20237 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57238 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58239 }
[email protected]6aa4a1c02010-01-15 18:49:58240}
241
[email protected]5656f8a2011-11-17 16:12:58242void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04243 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57244 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34245
[email protected]f04182f32010-12-10 19:12:07246 for (DownloadMap::iterator it = history_downloads_.begin();
247 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50248 if (!it->second->IsTemporary() &&
249 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57250 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34251 }
[email protected]8ddbd66a2010-05-21 16:38:34252}
253
[email protected]33d22102012-01-25 17:46:53254void DownloadManagerImpl::SearchByQuery(const content::DownloadQuery& query,
255 DownloadVector* results) {
256 query.Search(MapValueIteratorAdapter(history_downloads_.begin()),
257 MapValueIteratorAdapter(history_downloads_.end()), results);
258}
259
[email protected]5656f8a2011-11-17 16:12:58260void DownloadManagerImpl::SearchDownloads(const string16& query,
261 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26262 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42263
[email protected]f04182f32010-12-10 19:12:07264 for (DownloadMap::iterator it = history_downloads_.begin();
265 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42266 DownloadItem* download_item = it->second;
267
[email protected]c09a8fd2011-11-21 19:54:50268 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42269 continue;
270
271 // Display Incognito downloads only in Incognito window, and vice versa.
272 // The Incognito Downloads page will get the list of non-Incognito downloads
273 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50274 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42275 continue;
276
277 if (download_item->MatchesQuery(query_lower))
278 result->push_back(download_item);
279 }
[email protected]d3b12902010-08-16 23:39:42280}
281
initial.commit09911bf2008-07-26 23:55:29282// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58283bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03284 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29285 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
286 shutdown_needed_ = true;
287
[email protected]6d0c9fb2011-08-22 19:26:03288 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46289
[email protected]b39e7a88b2012-01-10 21:43:17290 // In test mode, there may be no ResourceDispatcherHost. In this case it's
291 // safe to avoid setting |file_manager_| because we only call a small set of
292 // functions, none of which need it.
[email protected]99907362012-01-11 05:41:40293 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get();
[email protected]b39e7a88b2012-01-10 21:43:17294 if (rdh) {
295 file_manager_ = rdh->download_file_manager();
296 DCHECK(file_manager_);
297 }
initial.commit09911bf2008-07-26 23:55:29298
initial.commit09911bf2008-07-26 23:55:29299 return true;
300}
301
[email protected]aa9881c2011-08-15 18:01:12302// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58303void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35305
[email protected]aa9881c2011-08-15 18:01:12306 if (delegate_->ShouldStartDownload(download_id))
307 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35308}
309
[email protected]5656f8a2011-11-17 16:12:58310void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312 for (DownloadMap::iterator it = history_downloads_.begin();
313 it != history_downloads_.end(); ++it) {
314 CheckForFileRemoval(it->second);
315 }
316}
317
[email protected]5656f8a2011-11-17 16:12:58318void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
320 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50321 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48322 BrowserThread::PostTask(
323 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58324 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50325 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17326 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48327 }
328}
329
[email protected]5656f8a2011-11-17 16:12:58330void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48331 int64 db_handle, const FilePath& path) {
332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
333 if (!file_util::PathExists(path)) {
334 BrowserThread::PostTask(
335 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58336 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
337 this,
338 db_handle));
[email protected]9fc114672011-06-15 08:17:48339 }
340}
341
[email protected]5656f8a2011-11-17 16:12:58342void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
344 DownloadMap::iterator it = history_downloads_.find(db_handle);
345 if (it != history_downloads_.end()) {
346 DownloadItem* download_item = it->second;
347 download_item->OnDownloadedFileRemoved();
348 }
349}
350
[email protected]443853c62011-12-22 19:22:41351void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29353
[email protected]4cd82f72011-05-23 19:15:01354 DownloadItem* download = GetActiveDownloadItem(download_id);
355 if (!download)
356 return;
357
358 VLOG(20) << __FUNCTION__ << "()"
359 << " download = " << download->DebugString(true);
360
[email protected]c09a8fd2011-11-21 19:54:50361 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01362
[email protected]c09a8fd2011-11-21 19:54:50363 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29364 // We must ask the user for the place to put the download.
[email protected]a62d42902012-01-24 17:24:38365 WebContents* contents = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:26366
[email protected]4cd82f72011-05-23 19:15:01367 // |id_ptr| will be deleted in either FileSelected() or
[email protected]93af2272011-09-21 18:29:17368 // FileSelectionCancelled().
[email protected]4cd82f72011-05-23 19:15:01369 int32* id_ptr = new int32;
370 *id_ptr = download_id;
[email protected]795b76a2011-12-14 16:52:53371 FilePath target_path;
372 // If |download| is a potentially dangerous file, then |suggested_path|
373 // contains the intermediate name instead of the final download
374 // filename. The latter is GetTargetName().
[email protected]a62d42902012-01-24 17:24:38375 if (download->GetDangerType() !=
376 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
[email protected]795b76a2011-12-14 16:52:53377 target_path = suggested_path.DirName().Append(download->GetTargetName());
378 else
379 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26380
[email protected]795b76a2011-12-14 16:52:53381 delegate_->ChooseDownloadPath(contents, target_path,
382 reinterpret_cast<void*>(id_ptr));
[email protected]f5920322011-03-24 20:34:16383 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]fed38252011-07-08 17:26:50384 SelectFileDialogDisplayed(download_id));
initial.commit09911bf2008-07-26 23:55:29385 } else {
386 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01387 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29388 }
389}
390
[email protected]37757c62011-12-20 20:07:12391content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58392 return browser_context_;
393}
394
395FilePath DownloadManagerImpl::LastDownloadPath() {
396 return last_download_path_;
397}
398
399void DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41400 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29401 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
402
[email protected]c09a8fd2011-11-21 19:54:50403 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29404 this, *info, new DownloadRequestHandle(request_handle),
405 browser_context_->IsOffTheRecord());
[email protected]2909e342011-10-29 00:46:53406 int32 download_id = info->download_id.local();
[email protected]4cd82f72011-05-23 19:15:01407 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]d8472d92011-08-26 20:15:20408
[email protected]a896ce32012-01-09 22:04:07409 CHECK_96627(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29410 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01411 active_downloads_[download_id] = download;
[email protected]c2e76012010-12-23 21:10:29412}
413
[email protected]fc03de22011-12-06 23:28:12414DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
415 const FilePath& main_file_path,
416 const GURL& page_url,
417 bool is_otr,
418 DownloadItem::Observer* observer) {
419 DownloadItem* download = new DownloadItemImpl(
420 this, main_file_path, page_url, is_otr, GetNextId());
421
422 download->AddObserver(observer);
423
424 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
425 downloads_.insert(download);
426 save_page_downloads_[download->GetId()] = download;
427
428 // Will notify the observer in the callback.
429 delegate_->AddItemToPersistentStore(download);
430
431 return download;
432}
433
[email protected]795b76a2011-12-14 16:52:53434// For non-safe downloads with no prompting, |chosen_file| is the intermediate
435// path for saving the in-progress download. The final target filename for these
436// is |download->GetTargetName()|. For all other downloads (non-safe downloads
437// for which we have prompted for a save location, and all safe downloads),
438// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58439void DownloadManagerImpl::ContinueDownloadWithPath(
440 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01442 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39443
[email protected]c09a8fd2011-11-21 19:54:50444 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29445
[email protected]70850c72011-01-11 17:31:27446 // NOTE(ahendrickson) Eventually |active_downloads_| will replace
447 // |in_progress_|, but we don't want to change the semantics yet.
[email protected]4cd82f72011-05-23 19:15:01448 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]70850c72011-01-11 17:31:27449 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01450 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27451
[email protected]4cd82f72011-05-23 19:15:01452 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20453 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01454 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01455
456 VLOG(20) << __FUNCTION__ << "()"
457 << " download = " << download->DebugString(true);
458
459 in_progress_[download_id] = download;
[email protected]5f8589fe2011-08-17 20:58:39460 UpdateDownloadProgress(); // Reflect entry into in_progress_.
initial.commit09911bf2008-07-26 23:55:29461
[email protected]adb2f3d12011-01-23 16:24:54462 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16463 FilePath download_path;
[email protected]ec865262011-08-23 20:01:48464 if (!delegate_->OverrideIntermediatePath(download, &download_path))
[email protected]c09a8fd2011-11-21 19:54:50465 download_path = download->GetFullPath();
[email protected]594cd7d2010-07-21 03:23:56466
[email protected]f5920322011-03-24 20:34:16467 BrowserThread::PostTask(
468 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17469 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12470 file_manager_, download->GetGlobalId(),
471 download_path));
[email protected]f5920322011-03-24 20:34:16472
473 download->Rename(download_path);
474
[email protected]2588ea9d2011-08-22 20:59:53475 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29476}
477
[email protected]443853c62011-12-22 19:22:41478void DownloadManagerImpl::UpdateDownload(int32 download_id,
479 int64 bytes_so_far,
480 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00481 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
483 DownloadMap::iterator it = active_downloads_.find(download_id);
484 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29485 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26486 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41487 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]5f8589fe2011-08-17 20:58:39488 UpdateDownloadProgress(); // Reflect size updates.
[email protected]2588ea9d2011-08-22 20:59:53489 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27490 }
initial.commit09911bf2008-07-26 23:55:29491 }
492}
493
[email protected]5656f8a2011-11-17 16:12:58494void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
495 int64 size,
496 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54497 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50498 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
499 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35500 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32501
[email protected]c4f02c42011-01-24 21:55:06502 // If it's not in active_downloads_, that means it was cancelled; just
503 // ignore the notification.
504 if (active_downloads_.count(download_id) == 0)
505 return;
506
[email protected]adb2f3d12011-01-23 16:24:54507 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37508 download->OnAllDataSaved(size, hash);
509 delegate_->OnResponseCompleted(download);
[email protected]b09f1282011-09-14 00:37:45510
[email protected]fc03de22011-12-06 23:28:12511 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54512}
[email protected]9ccbb372008-10-10 18:50:32513
[email protected]fc03de22011-12-06 23:28:12514void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]a896ce32012-01-09 22:04:07515 // TODO(rdsmith): Change to DCHECK after http://crbug.com/96627 resolved.
[email protected]c09a8fd2011-11-21 19:54:50516 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]7d413112011-06-16 18:50:17517 CHECK(!ContainsKey(downloads_, download));
[email protected]c09a8fd2011-11-21 19:54:50518 CHECK(!ContainsKey(active_downloads_, download->GetId()));
519 CHECK(!ContainsKey(in_progress_, download->GetId()));
520 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17521 return;
522 }
523
524 // Should be in downloads_ if we're not REMOVING.
525 CHECK(ContainsKey(downloads_, download));
526
527 // Check history_downloads_ consistency.
[email protected]c09a8fd2011-11-21 19:54:50528 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
529 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17530 } else {
[email protected]fc03de22011-12-06 23:28:12531 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17532 it != history_downloads_.end(); ++it) {
[email protected]a896ce32012-01-09 22:04:07533 CHECK_96627(it->second != download);
[email protected]7d413112011-06-16 18:50:17534 }
535 }
536
[email protected]c09a8fd2011-11-21 19:54:50537 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34538 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50539 if (ContainsKey(active_downloads_, download->GetId())) {
540 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle)
541 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
542 if (DownloadItem::IN_PROGRESS != download->GetState())
543 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07544 }
[email protected]c09a8fd2011-11-21 19:54:50545 if (DownloadItem::IN_PROGRESS == download->GetState())
546 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59547}
548
[email protected]5656f8a2011-11-17 16:12:58549bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54550 // If we don't have all the data, the download is not ready for
551 // completion.
[email protected]c09a8fd2011-11-21 19:54:50552 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54553 return false;
[email protected]6a7fb042010-02-01 16:30:47554
[email protected]9d7ef802011-02-25 19:03:35555 // If the download is dangerous, but not yet validated, it's not ready for
556 // completion.
[email protected]c09a8fd2011-11-21 19:54:50557 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35558 return false;
559
[email protected]adb2f3d12011-01-23 16:24:54560 // If the download isn't active (e.g. has been cancelled) it's not
561 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50562 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54563 return false;
564
565 // If the download hasn't been inserted into the history system
566 // (which occurs strictly after file name determination, intermediate
567 // file rename, and UI display) then it's not ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50568 if (download->GetDbHandle() == DownloadItem::kUninitializedHandle)
[email protected]7054b592011-06-22 14:46:42569 return false;
570
571 return true;
[email protected]adb2f3d12011-01-23 16:24:54572}
573
[email protected]5656f8a2011-11-17 16:12:58574void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54575 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
576 VLOG(20) << __FUNCTION__ << "()" << " download = "
577 << download->DebugString(false);
578
579 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32580 return;
[email protected]9ccbb372008-10-10 18:50:32581
[email protected]adb2f3d12011-01-23 16:24:54582 // TODO(rdsmith): DCHECK that we only pass through this point
583 // once per download. The natural way to do this is by a state
584 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56585
[email protected]adb2f3d12011-01-23 16:24:54586 // Confirm we're in the proper set of states to be here;
[email protected]9d7ef802011-02-25 19:03:35587 // in in_progress_, have all data, have a history handle, (validated or safe).
[email protected]c09a8fd2011-11-21 19:54:50588 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
589 DCHECK_EQ(1u, in_progress_.count(download->GetId()));
590 DCHECK(download->AllDataSaved());
591 DCHECK(download->GetDbHandle() != DownloadItem::kUninitializedHandle);
592 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54593
[email protected]c2918652011-11-01 18:50:23594 // Give the delegate a chance to override.
595 if (!delegate_->ShouldCompleteDownload(download))
596 return;
597
[email protected]adb2f3d12011-01-23 16:24:54598 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
599 << download->DebugString(false);
600
601 // Remove the id from in_progress
[email protected]c09a8fd2011-11-21 19:54:50602 in_progress_.erase(download->GetId());
[email protected]5f8589fe2011-08-17 20:58:39603 UpdateDownloadProgress(); // Reflect removal from in_progress_.
[email protected]adb2f3d12011-01-23 16:24:54604
[email protected]2588ea9d2011-08-22 20:59:53605 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54606
[email protected]f5920322011-03-24 20:34:16607 // Finish the download.
[email protected]48837962011-04-19 17:03:29608 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32609}
610
[email protected]fc03de22011-12-06 23:28:12611void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27612 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21613 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53614 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12615 active_downloads_.erase(download->GetId());
616 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27617}
618
[email protected]5656f8a2011-11-17 16:12:58619void DownloadManagerImpl::OnDownloadRenamedToFinalName(
620 int download_id,
621 const FilePath& full_path,
622 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50623 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16624 << " full_path = \"" << full_path.value() << "\""
625 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18626 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16627
[email protected]2e030682010-07-23 19:45:36628 DownloadItem* item = GetDownloadItem(download_id);
629 if (!item)
630 return;
[email protected]6cade212008-12-03 00:32:22631
[email protected]a62d42902012-01-24 17:24:38632 if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
[email protected]795b76a2011-12-14 16:52:53633 item->PromptUserForSaveLocation()) {
634 DCHECK_EQ(0, uniquifier)
635 << "We should not uniquify user supplied filenames or safe filenames "
636 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02637 }
638
[email protected]fabf36d22011-10-28 21:50:17639 BrowserThread::PostTask(
640 BrowserThread::FILE, FROM_HERE,
641 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50642 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32643
[email protected]f5920322011-03-24 20:34:16644 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50645 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32646
[email protected]f5920322011-03-24 20:34:16647 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53648 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29649}
650
[email protected]5656f8a2011-11-17 16:12:58651void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17652 DownloadItem* download = GetActiveDownload(download_id);
653 // A cancel at the right time could remove the download from the
654 // |active_downloads_| map before we get here.
655 if (!download)
656 return;
657
658 download->Cancel(true);
659}
660
[email protected]fc03de22011-12-06 23:28:12661void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20662 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20663
664 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50665 << " download = " << download->DebugString(true);
666
[email protected]93af2272011-09-21 18:29:17667 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21668 // This function is called from the DownloadItem, so DI state
669 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12670 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29671
[email protected]15d90ba2011-11-03 03:41:55672 if (file_manager_)
673 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29674}
675
[email protected]5656f8a2011-11-17 16:12:58676void DownloadManagerImpl::OnDownloadInterrupted(int32 download_id,
677 int64 size,
[email protected]0afff032012-01-06 20:55:00678 const std::string& hash_state,
[email protected]5656f8a2011-11-17 16:12:58679 InterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21680 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
681
682 DownloadItem* download = GetActiveDownload(download_id);
683 if (!download)
684 return;
685
[email protected]be76b7e2011-10-13 12:57:57686 VLOG(20) << __FUNCTION__ << "()"
687 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50688 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21689 << " size = " << size
690 << " download = " << download->DebugString(true);
691
[email protected]93af2272011-09-21 18:29:17692 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41693 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17694 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21695}
696
[email protected]5656f8a2011-11-17 16:12:58697DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26698 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
699 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26700 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21701 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26702
703 DownloadItem* download = it->second;
704
[email protected]47a881b2011-08-29 22:59:21705 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50706 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01707
[email protected]47a881b2011-08-29 22:59:21708 return download;
709}
[email protected]54610672011-07-18 18:24:43710
[email protected]5656f8a2011-11-17 16:12:58711void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17712 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
713 DCHECK(download);
714
715 // Clean up will happen when the history system create callback runs if we
716 // don't have a valid db_handle yet.
[email protected]c09a8fd2011-11-21 19:54:50717 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
718 in_progress_.erase(download->GetId());
719 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17720 UpdateDownloadProgress(); // Reflect removal from in_progress_.
721 delegate_->UpdateItemInPersistentStore(download);
722 }
723}
724
[email protected]fd3a82832012-01-19 20:35:12725bool DownloadManagerImpl::GenerateFileHash() {
726 return delegate_->GenerateFileHash();
727}
728
[email protected]5656f8a2011-11-17 16:12:58729content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
730 return delegate_;
731}
732
733void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17734 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35735 delegate_ = delegate;
736}
737
[email protected]5656f8a2011-11-17 16:12:58738void DownloadManagerImpl::UpdateDownloadProgress() {
[email protected]5f8589fe2011-08-17 20:58:39739 delegate_->DownloadProgressUpdated();
[email protected]6a7fb042010-02-01 16:30:47740}
741
[email protected]5656f8a2011-11-17 16:12:58742int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04743 const DownloadVector& pending_deletes) {
744 if (pending_deletes.empty())
745 return 0;
746
747 // Delete from internal maps.
748 for (DownloadVector::const_iterator it = pending_deletes.begin();
749 it != pending_deletes.end();
750 ++it) {
751 DownloadItem* download = *it;
752 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50753 history_downloads_.erase(download->GetDbHandle());
754 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04755 downloads_.erase(download);
756 }
757
758 // Tell observers to refresh their views.
759 NotifyModelChanged();
760
761 // Delete the download items themselves.
762 const int num_deleted = static_cast<int>(pending_deletes.size());
763 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
764 return num_deleted;
765}
766
[email protected]fc03de22011-12-06 23:28:12767void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
768 if (history_downloads_.find(download->GetDbHandle()) ==
769 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17770 return;
771
772 // Make history update.
[email protected]93af2272011-09-21 18:29:17773 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29774
775 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04776 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07777 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29778}
779
[email protected]fd3a82832012-01-19 20:35:12780int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
781 base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53782 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29783
[email protected]a312a442010-12-15 23:40:33784 // All downloads visible to the user will be in the history,
785 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04786 DownloadVector pending_deletes;
787 for (DownloadMap::const_iterator it = history_downloads_.begin();
788 it != history_downloads_.end();
789 ++it) {
initial.commit09911bf2008-07-26 23:55:29790 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50791 if (download->GetStartTime() >= remove_begin &&
792 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04793 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12794 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28795 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29796 }
initial.commit09911bf2008-07-26 23:55:29797 }
[email protected]6d0146c2011-08-04 19:13:04798 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29799}
800
[email protected]fd3a82832012-01-19 20:35:12801int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59802 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29803}
804
[email protected]5656f8a2011-11-17 16:12:58805int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06806 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12807 // The null times make the date range unbounded.
808 return RemoveDownloadsBetween(base::Time(), base::Time());
809}
810
initial.commit09911bf2008-07-26 23:55:29811// Initiate a download of a specific URL. We send the request to the
812// ResourceDispatcherHost, and let it send us responses like a regular
813// download.
[email protected]5656f8a2011-11-17 16:12:58814void DownloadManagerImpl::DownloadUrl(const GURL& url,
815 const GURL& referrer,
816 const std::string& referrer_charset,
[email protected]bb81f382012-01-03 22:45:44817 WebContents* web_contents) {
[email protected]ae8945192010-07-20 16:56:26818 DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(),
[email protected]bb81f382012-01-03 22:45:44819 web_contents);
[email protected]6aa4a1c02010-01-15 18:49:58820}
821
[email protected]5656f8a2011-11-17 16:12:58822void DownloadManagerImpl::DownloadUrlToFile(const GURL& url,
823 const GURL& referrer,
824 const std::string& referrer_charset,
825 const DownloadSaveInfo& save_info,
[email protected]fbc5e5f92012-01-02 06:08:32826 WebContents* web_contents) {
[email protected]c79a0c02011-08-22 22:37:37827 ResourceDispatcherHost* resource_dispatcher_host =
[email protected]99907362012-01-11 05:41:40828 ResourceDispatcherHost::Get();
[email protected]443853c62011-12-22 19:22:41829
[email protected]ed24fad2011-05-10 22:44:01830 // We send a pointer to content::ResourceContext, instead of the usual
831 // reference, so that a copy of the object isn't made.
[email protected]fabf36d22011-10-28 21:50:17832 // base::Bind can't handle 7 args, so we use URLParams and RenderParams.
833 BrowserThread::PostTask(
834 BrowserThread::IO, FROM_HERE,
835 base::Bind(&BeginDownload,
836 URLParams(url, referrer), save_info, resource_dispatcher_host,
[email protected]fbc5e5f92012-01-02 06:08:32837 RenderParams(web_contents->GetRenderProcessHost()->GetID(),
838 web_contents->GetRenderViewHost()->routing_id()),
839 &web_contents->GetBrowserContext()->GetResourceContext()));
initial.commit09911bf2008-07-26 23:55:29840}
841
[email protected]5656f8a2011-11-17 16:12:58842void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29843 observers_.AddObserver(observer);
844 observer->ModelChanged();
845}
846
[email protected]5656f8a2011-11-17 16:12:58847void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29848 observers_.RemoveObserver(observer);
849}
850
[email protected]5656f8a2011-11-17 16:12:58851bool DownloadManagerImpl::IsDownloadProgressKnown() const {
[email protected]45f432e942011-10-25 18:17:22852 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02853 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50854 if (i->second->GetTotalBytes() <= 0)
[email protected]073ed7b2010-09-27 09:20:02855 return false;
856 }
857
858 return true;
859}
860
[email protected]5656f8a2011-11-17 16:12:58861int64 DownloadManagerImpl::GetInProgressDownloadCount() const {
[email protected]073ed7b2010-09-27 09:20:02862 return in_progress_.size();
863}
864
[email protected]5656f8a2011-11-17 16:12:58865int64 DownloadManagerImpl::GetReceivedDownloadBytes() const {
[email protected]073ed7b2010-09-27 09:20:02866 DCHECK(IsDownloadProgressKnown());
867 int64 received_bytes = 0;
[email protected]45f432e942011-10-25 18:17:22868 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02869 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50870 received_bytes += i->second->GetReceivedBytes();
[email protected]073ed7b2010-09-27 09:20:02871 }
872 return received_bytes;
873}
874
[email protected]5656f8a2011-11-17 16:12:58875int64 DownloadManagerImpl::GetTotalDownloadBytes() const {
[email protected]073ed7b2010-09-27 09:20:02876 DCHECK(IsDownloadProgressKnown());
877 int64 total_bytes = 0;
[email protected]45f432e942011-10-25 18:17:22878 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02879 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50880 total_bytes += i->second->GetTotalBytes();
[email protected]073ed7b2010-09-27 09:20:02881 }
882 return total_bytes;
883}
884
[email protected]5656f8a2011-11-17 16:12:58885void DownloadManagerImpl::FileSelected(const FilePath& path, void* params) {
[email protected]4cd82f72011-05-23 19:15:01886 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
887
888 int32* id_ptr = reinterpret_cast<int32*>(params);
889 DCHECK(id_ptr != NULL);
890 int32 download_id = *id_ptr;
891 delete id_ptr;
892
893 DownloadItem* download = GetActiveDownloadItem(download_id);
894 if (!download)
895 return;
896 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
897 << " download = " << download->DebugString(true);
898
[email protected]c09a8fd2011-11-21 19:54:50899 if (download->PromptUserForSaveLocation())
[email protected]7ae7c2cb2009-01-06 23:31:41900 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35901
[email protected]4cd82f72011-05-23 19:15:01902 // Make sure the initial file name is set only once.
903 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29904}
905
[email protected]5656f8a2011-11-17 16:12:58906void DownloadManagerImpl::FileSelectionCanceled(void* params) {
initial.commit09911bf2008-07-26 23:55:29907 // The user didn't pick a place to save the file, so need to cancel the
908 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01909 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
910 int32* id_ptr = reinterpret_cast<int32*>(params);
911 DCHECK(id_ptr != NULL);
912 int32 download_id = *id_ptr;
913 delete id_ptr;
914
915 DownloadItem* download = GetActiveDownloadItem(download_id);
916 if (!download)
917 return;
918
919 VLOG(20) << __FUNCTION__ << "()"
920 << " download = " << download->DebugString(true);
921
[email protected]93af2272011-09-21 18:29:17922 // TODO(ahendrickson) -- This currently has no effect, as the download is
923 // not put on the active list until the file selection is complete. Need
924 // to put it on the active list earlier in the process.
925 RemoveFromActiveList(download);
926
927 download->OffThreadCancel(file_manager_);
[email protected]4cd82f72011-05-23 19:15:01928}
929
initial.commit09911bf2008-07-26 23:55:29930// Operations posted to us from the history service ----------------------------
931
932// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25933// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58934void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25935 std::vector<DownloadPersistentStoreInfo>* entries) {
[email protected]d8472d92011-08-26 20:15:20936 // TODO(rdsmith): Remove this and related logic when
[email protected]a896ce32012-01-09 22:04:07937 // http://crbug.com/96627 is fixed.
[email protected]d8472d92011-08-26 20:15:20938 largest_db_handle_in_history_ = 0;
939
initial.commit09911bf2008-07-26 23:55:29940 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]fc03de22011-12-06 23:28:12941 DownloadItem* download = new DownloadItemImpl(
942 this, GetNextId(), entries->at(i));
[email protected]a896ce32012-01-09 22:04:07943 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]f04182f32010-12-10 19:12:07944 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50945 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50946 VLOG(20) << __FUNCTION__ << "()" << i << ">"
947 << " download = " << download->DebugString(true);
[email protected]d8472d92011-08-26 20:15:20948
[email protected]c09a8fd2011-11-21 19:54:50949 if (download->GetDbHandle() > largest_db_handle_in_history_)
950 largest_db_handle_in_history_ = download->GetDbHandle();
initial.commit09911bf2008-07-26 23:55:29951 }
[email protected]b0ab1d42010-02-24 19:29:28952 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48953 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29954}
955
[email protected]5656f8a2011-11-17 16:12:58956void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
957 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27958 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d2a8fb72010-01-21 05:31:42959
[email protected]a896ce32012-01-09 22:04:07960 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]1e9fe7ff2011-06-24 17:37:33961 // is fixed.
[email protected]2588ea9d2011-08-22 20:59:53962 CHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33963
[email protected]da4a5582011-10-17 19:08:06964 download_stats::RecordHistorySize(history_downloads_.size());
965
[email protected]c09a8fd2011-11-21 19:54:50966 DCHECK(download->GetDbHandle() == DownloadItem::kUninitializedHandle);
967 download->SetDbHandle(db_handle);
[email protected]5bcd73eb2011-03-23 21:14:02968
[email protected]a896ce32012-01-09 22:04:07969 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]d8472d92011-08-26 20:15:20970 // is fixed.
[email protected]a896ce32012-01-09 22:04:07971 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]c09a8fd2011-11-21 19:54:50972 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04973
974 // Show in the appropriate browser UI.
975 // This includes buttons to save or cancel, for a dangerous download.
976 ShowDownloadInBrowser(download);
977
978 // Inform interested objects about the new download.
979 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19980}
981
[email protected]2588ea9d2011-08-22 20:59:53982
[email protected]5656f8a2011-11-17 16:12:58983void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
984 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53985 if (save_page_downloads_.count(download_id)) {
986 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
987 } else if (active_downloads_.count(download_id)) {
988 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
989 }
990 // It's valid that we don't find a matching item, i.e. on shutdown.
991}
992
[email protected]f9a45b02011-06-30 23:49:19993// Once the new DownloadItem's creation info has been committed to the history
994// service, we associate the DownloadItem with the db handle, update our
995// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:58996void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
997 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:19998 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:45999 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:171000 if (!download)
[email protected]19420cc2011-07-18 17:43:451001 return;
[email protected]54610672011-07-18 18:24:431002
1003 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
1004 << " download_id = " << download_id
1005 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:191006
[email protected]a896ce32012-01-09 22:04:071007 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201008 int64 largest_handle = largest_db_handle_in_history_;
1009 base::debug::Alias(&largest_handle);
[email protected]e5107ce2011-09-19 20:36:131010 int32 matching_item_download_id
1011 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:501012 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:131013 base::debug::Alias(&matching_item_download_id);
1014
[email protected]a896ce32012-01-09 22:04:071015 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201016
[email protected]f9a45b02011-06-30 23:49:191017 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:291018
[email protected]93af2272011-09-21 18:29:171019 // If the download is still in progress, try to complete it.
1020 //
1021 // Otherwise, download has been cancelled or interrupted before we've
1022 // received the DB handle. We post one final message to the history
1023 // service so that it can be properly in sync with the DownloadItem's
1024 // completion status, and also inform any observers so that they get
1025 // more than just the start notification.
1026 if (download->IsInProgress()) {
1027 MaybeCompleteDownload(download);
1028 } else {
[email protected]a896ce32012-01-09 22:04:071029 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]93af2272011-09-21 18:29:171030 // is fixed.
1031 CHECK(download->IsCancelled())
1032 << " download = " << download->DebugString(true);
1033 in_progress_.erase(download_id);
1034 active_downloads_.erase(download_id);
1035 delegate_->UpdateItemInPersistentStore(download);
1036 download->UpdateObservers();
1037 }
initial.commit09911bf2008-07-26 23:55:291038}
1039
[email protected]5656f8a2011-11-17 16:12:581040void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]8ddbd66a2010-05-21 16:38:341041 // The 'contents' may no longer exist if the user closed the tab before we
[email protected]99cb7f82011-07-28 17:27:261042 // get this start completion event.
[email protected]a62d42902012-01-24 17:24:381043 WebContents* content = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:261044
1045 // If the contents no longer exists, we ask the embedder to suggest another
1046 // tab.
[email protected]da1a27b2011-07-29 23:16:331047 if (!content)
[email protected]ef9572e2012-01-04 22:14:121048 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:531049
[email protected]0bfbf882011-12-22 18:19:271050 if (content && content->GetDelegate())
1051 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531052}
1053
[email protected]5656f8a2011-11-17 16:12:581054int DownloadManagerImpl::InProgressCount() const {
1055 return static_cast<int>(in_progress_.size());
1056}
1057
[email protected]6cade212008-12-03 00:32:221058// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581059void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411060 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381061}
[email protected]b0ab1d42010-02-24 19:29:281062
[email protected]5656f8a2011-11-17 16:12:581063void DownloadManagerImpl::NotifyModelChanged() {
[email protected]b0ab1d42010-02-24 19:29:281064 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged());
1065}
1066
[email protected]5656f8a2011-11-17 16:12:581067DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011068 // The |history_downloads_| map is indexed by the download's db_handle,
1069 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071070 for (DownloadMap::iterator it = history_downloads_.begin();
1071 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361072 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501073 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361074 return item;
1075 }
1076 return NULL;
1077}
1078
[email protected]5656f8a2011-11-17 16:12:581079DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361080 if (ContainsKey(active_downloads_, download_id))
1081 return active_downloads_[download_id];
1082 return NULL;
[email protected]4cd82f72011-05-23 19:15:011083}
1084
[email protected]57fd1252010-12-23 17:24:091085// Confirm that everything in all maps is also in |downloads_|, and that
1086// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581087void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071088#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091089 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041090 const DownloadMap* input_maps[] = {&active_downloads_,
1091 &history_downloads_,
1092 &save_page_downloads_};
1093 DownloadSet active_set, history_set, save_page_set;
1094 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1095 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091096 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1097 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041098 it != input_maps[i]->end(); ++it) {
1099 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071100 }
1101 }
[email protected]57fd1252010-12-23 17:24:091102
1103 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091104 DownloadSet downloads_union;
1105 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1106 DownloadSet remainder;
1107 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1108 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1109 downloads_.begin(), downloads_.end(),
1110 insert_it);
1111 DCHECK(remainder.empty());
1112 std::insert_iterator<DownloadSet>
1113 insert_union(downloads_union, downloads_union.end());
1114 std::set_union(downloads_union.begin(), downloads_union.end(),
1115 all_sets[i]->begin(), all_sets[i]->end(),
1116 insert_union);
1117 }
1118
1119 // Is everything in downloads_ present in one of the other sets?
1120 DownloadSet remainder;
1121 std::insert_iterator<DownloadSet>
1122 insert_remainder(remainder, remainder.begin());
1123 std::set_difference(downloads_.begin(), downloads_.end(),
1124 downloads_union.begin(), downloads_union.end(),
1125 insert_remainder);
1126 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071127#endif
1128}
1129
[email protected]6d0146c2011-08-04 19:13:041130// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531131// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041132// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531133// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1134// that the history event is update regardless of the order in which these two
1135// events complete.
[email protected]6d0146c2011-08-04 19:13:041136// If something removes the download item from the download manager (Remove,
1137// Shutdown) the result will be that the SavePage system will not be able to
1138// properly update the download item (which no longer exists) or the download
1139// history, but the action will complete properly anyway. This may lead to the
1140// history entry being wrong on a reload of chrome (specifically in the case of
1141// Initiation -> History Callback -> Removal -> Completion), but there's no way
1142// to solve that without canceling on Remove (which would then update the DB).
1143
[email protected]5656f8a2011-11-17 16:12:581144void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1145 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1147
1148 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1149 // This can happen if the download manager is shutting down and all maps
1150 // have been cleared.
1151 if (it == save_page_downloads_.end())
1152 return;
1153
1154 DownloadItem* download = it->second;
1155 if (!download) {
1156 NOTREACHED();
1157 return;
1158 }
1159
[email protected]a896ce32012-01-09 22:04:071160 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201161 int64 largest_handle = largest_db_handle_in_history_;
1162 base::debug::Alias(&largest_handle);
[email protected]a896ce32012-01-09 22:04:071163 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201164
[email protected]6d0146c2011-08-04 19:13:041165 AddDownloadItemToHistory(download, db_handle);
1166
1167 // Finalize this download if it finished before the history callback.
1168 if (!download->IsInProgress())
1169 SavePageDownloadFinished(download);
1170}
1171
[email protected]5656f8a2011-11-17 16:12:581172void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]c09a8fd2011-11-21 19:54:501173 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
[email protected]2588ea9d2011-08-22 20:59:531174 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501175 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1176 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041177
1178 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071179 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041180 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531181 content::Source<DownloadManager>(this),
1182 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041183 }
1184}
[email protected]da4a5582011-10-17 19:08:061185
[email protected]fc03de22011-12-06 23:28:121186void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061187 delegate_->UpdateItemInPersistentStore(download);
1188 int num_unopened = 0;
1189 for (DownloadMap::iterator it = history_downloads_.begin();
1190 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501191 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061192 ++num_unopened;
1193 }
1194 download_stats::RecordOpensOutstanding(num_unopened);
1195}
[email protected]5656f8a2011-11-17 16:12:581196
1197void DownloadManagerImpl::SetFileManager(DownloadFileManager* file_manager) {
1198 file_manager_ = file_manager;
1199}