blob: afea786d7fe041c85891aa9423180c23e942a113 [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]da4a5582011-10-17 19:08:0623#include "content/browser/download/download_stats.h"
[email protected]b3c41c0b2012-03-06 15:48:3224#include "content/browser/renderer_host/render_view_host_impl.h"
[email protected]ea114722012-03-12 01:11:2525#include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
[email protected]93ddb3c2012-04-11 21:44:2926#include "content/browser/web_contents/web_contents_impl.h"
[email protected]ccb797302011-12-15 16:55:1127#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4928#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4429#include "content/public/browser/content_browser_client.h"
[email protected]bf3b08a2012-03-08 01:52:3430#include "content/public/browser/download_interrupt_reasons.h"
[email protected]1bd0ef12011-10-20 05:24:1731#include "content/public/browser/download_manager_delegate.h"
[email protected]8da82ea2012-03-11 22:16:5232#include "content/public/browser/download_persistent_store_info.h"
[email protected]ad50def52011-10-19 23:17:0733#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1634#include "content/public/browser/notification_types.h"
[email protected]f3b1a082011-11-18 00:34:3035#include "content/public/browser/render_process_host.h"
[email protected]0bfbf882011-12-22 18:19:2736#include "content/public/browser/web_contents_delegate.h"
[email protected]27678b2a2012-02-04 22:09:1437#include "net/base/upload_data.h"
initial.commit09911bf2008-07-26 23:55:2938
[email protected]631bb742011-11-02 11:29:3939using content::BrowserThread;
[email protected]98e814062012-01-27 00:35:4240using content::DownloadId;
[email protected]e582fdd2011-12-20 16:48:1741using content::DownloadItem;
[email protected]8da82ea2012-03-11 22:16:5242using content::DownloadPersistentStoreInfo;
[email protected]ea114722012-03-12 01:11:2543using content::ResourceDispatcherHostImpl;
[email protected]2a6bc3e2011-12-28 23:51:3344using content::WebContents;
[email protected]631bb742011-11-02 11:29:3945
[email protected]a0ce3282011-08-19 20:49:5246namespace {
47
[email protected]fabf36d22011-10-28 21:50:1748// Param structs exist because base::Bind can only handle 6 args.
49struct URLParams {
[email protected]89e6aa72012-03-12 22:51:3350 URLParams(const GURL& url, const GURL& referrer, int64 post_id, bool cache)
51 : url_(url), referrer_(referrer), post_id_(post_id), prefer_cache_(cache) {}
[email protected]fabf36d22011-10-28 21:50:1752 GURL url_;
53 GURL referrer_;
[email protected]27678b2a2012-02-04 22:09:1454 int64 post_id_;
[email protected]89e6aa72012-03-12 22:51:3355 bool prefer_cache_;
[email protected]fabf36d22011-10-28 21:50:1756};
57
58struct RenderParams {
59 RenderParams(int rpi, int rvi)
60 : render_process_id_(rpi), render_view_id_(rvi) {}
61 int render_process_id_;
62 int render_view_id_;
63};
64
[email protected]89e6aa72012-03-12 22:51:3365void BeginDownload(
66 const URLParams& url_params,
[email protected]29a5ffc82012-03-13 19:35:5867 const content::DownloadSaveInfo& save_info,
[email protected]89e6aa72012-03-12 22:51:3368 ResourceDispatcherHostImpl* resource_dispatcher_host,
69 const RenderParams& render_params,
70 content::ResourceContext* context,
71 const content::DownloadManager::OnStartedCallback& callback) {
[email protected]c1ba99842012-01-19 20:56:0572 scoped_ptr<net::URLRequest> request(
73 new net::URLRequest(url_params.url_, resource_dispatcher_host));
[email protected]fabf36d22011-10-28 21:50:1774 request->set_referrer(url_params.referrer_.spec());
[email protected]27678b2a2012-02-04 22:09:1475 if (url_params.post_id_ >= 0) {
76 // The POST in this case does not have an actual body, and only works
77 // when retrieving data from cache. This is done because we don't want
78 // to do a re-POST without user consent, and currently don't have a good
79 // plan on how to display the UI for that.
[email protected]89e6aa72012-03-12 22:51:3380 DCHECK(url_params.prefer_cache_);
[email protected]27678b2a2012-02-04 22:09:1481 request->set_method("POST");
82 scoped_refptr<net::UploadData> upload_data = new net::UploadData();
83 upload_data->set_identifier(url_params.post_id_);
84 request->set_upload(upload_data);
85 }
[email protected]c79a0c02011-08-22 22:37:3786 resource_dispatcher_host->BeginDownload(
[email protected]ea114722012-03-12 01:11:2587 request.Pass(),
88 context,
[email protected]fabf36d22011-10-28 21:50:1789 render_params.render_process_id_,
90 render_params.render_view_id_,
[email protected]89e6aa72012-03-12 22:51:3391 url_params.prefer_cache_,
[email protected]ea114722012-03-12 01:11:2592 save_info,
[email protected]89e6aa72012-03-12 22:51:3393 callback);
[email protected]a0ce3282011-08-19 20:49:5294}
95
[email protected]33d22102012-01-25 17:46:5396class MapValueIteratorAdapter {
97 public:
98 explicit MapValueIteratorAdapter(
99 base::hash_map<int64, DownloadItem*>::const_iterator iter)
100 : iter_(iter) {
101 }
102 ~MapValueIteratorAdapter() {}
103
104 DownloadItem* operator*() { return iter_->second; }
105
106 MapValueIteratorAdapter& operator++() {
107 ++iter_;
108 return *this;
109 }
110
111 bool operator!=(const MapValueIteratorAdapter& that) const {
112 return iter_ != that.iter_;
113 }
114
115 private:
116 base::hash_map<int64, DownloadItem*>::const_iterator iter_;
117 // Allow copy and assign.
118};
119
[email protected]5948e1a2012-03-10 00:19:18120void EnsureNoPendingDownloadsOnFile(scoped_refptr<DownloadFileManager> dfm,
121 bool* result) {
122 if (dfm->NumberOfActiveDownloads())
123 *result = false;
124 BrowserThread::PostTask(
125 BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure());
126}
127
[email protected]0a5c9112012-03-12 17:49:02128void EnsureNoPendingDownloadJobsOnIO(bool* result) {
[email protected]5948e1a2012-03-10 00:19:18129 scoped_refptr<DownloadFileManager> download_file_manager =
[email protected]ea114722012-03-12 01:11:25130 ResourceDispatcherHostImpl::Get()->download_file_manager();
[email protected]5948e1a2012-03-10 00:19:18131 BrowserThread::PostTask(
132 BrowserThread::FILE, FROM_HERE,
133 base::Bind(&EnsureNoPendingDownloadsOnFile,
134 download_file_manager, result));
135}
136
[email protected]a0ce3282011-08-19 20:49:52137} // namespace
138
[email protected]99907362012-01-11 05:41:40139namespace content {
140
141// static
142DownloadManager* DownloadManager::Create(
[email protected]ef17c9a2012-02-09 05:08:09143 content::DownloadManagerDelegate* delegate,
144 net::NetLog* net_log) {
145 return new DownloadManagerImpl(delegate, net_log);
[email protected]99907362012-01-11 05:41:40146}
147
[email protected]5948e1a2012-03-10 00:19:18148bool DownloadManager::EnsureNoPendingDownloadsForTesting() {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
150 bool result = true;
151 BrowserThread::PostTask(
152 BrowserThread::IO, FROM_HERE,
[email protected]0a5c9112012-03-12 17:49:02153 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result));
[email protected]5948e1a2012-03-10 00:19:18154 MessageLoop::current()->Run();
155 return result;
156}
157
[email protected]99907362012-01-11 05:41:40158} // namespace content
159
[email protected]5656f8a2011-11-17 16:12:58160DownloadManagerImpl::DownloadManagerImpl(
[email protected]ef17c9a2012-02-09 05:08:09161 content::DownloadManagerDelegate* delegate,
162 net::NetLog* net_log)
[email protected]5656f8a2011-11-17 16:12:58163 : shutdown_needed_(false),
164 browser_context_(NULL),
165 file_manager_(NULL),
[email protected]5656f8a2011-11-17 16:12:58166 delegate_(delegate),
[email protected]ef17c9a2012-02-09 05:08:09167 net_log_(net_log) {
initial.commit09911bf2008-07-26 23:55:29168}
169
[email protected]5656f8a2011-11-17 16:12:58170DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13171 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29172}
173
[email protected]5656f8a2011-11-17 16:12:58174DownloadId DownloadManagerImpl::GetNextId() {
[email protected]98e814062012-01-27 00:35:42175 return delegate_->GetNextId();
[email protected]2909e342011-10-29 00:46:53176}
177
[email protected]fc03de22011-12-06 23:28:12178bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
179 return delegate_->ShouldOpenDownload(item);
180}
181
182bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
183 return delegate_->ShouldOpenFileBasedOnExtension(path);
184}
185
[email protected]5656f8a2011-11-17 16:12:58186void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50187 VLOG(20) << __FUNCTION__ << "()"
188 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13189 if (!shutdown_needed_)
190 return;
191 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29192
[email protected]75e51b52012-02-04 16:57:54193 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
[email protected]fb4f8d902011-09-16 06:07:08194 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13195
196 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18197 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17198 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
199 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13200 }
initial.commit09911bf2008-07-26 23:55:29201
[email protected]f04182f32010-12-10 19:12:07202 AssertContainersConsistent();
203
204 // Go through all downloads in downloads_. Dangerous ones we need to
205 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09206 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07207 DownloadItem* download = *it;
208
209 // Save iterator from potential erases in this set done by called code.
210 // Iterators after an erasure point are still valid for lists and
211 // associative containers such as sets.
212 it++;
213
[email protected]c09a8fd2011-11-21 19:54:50214 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29215 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07216 // The user hasn't accepted it, so we need to remove it
217 // from the disk. This may or may not result in it being
218 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12219 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07220 // removes and deletes it if it's known to the history service)
221 // so the only thing we know after calling this function is that
222 // the download was deleted if-and-only-if it was removed
223 // from all queues.
[email protected]303077002011-04-19 23:21:01224 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26225 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17226 download->Cancel(false);
227 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29228 }
229 }
230
[email protected]f04182f32010-12-10 19:12:07231 // At this point, all dangerous downloads have had their files removed
232 // and all in progress downloads have been cancelled. We can now delete
233 // anything left.
[email protected]9ccbb372008-10-10 18:50:32234
[email protected]5cd11b6e2011-06-10 20:30:59235 // Copy downloads_ to separate container so as not to set off checks
236 // in DownloadItem destruction.
237 DownloadSet downloads_to_delete;
238 downloads_to_delete.swap(downloads_);
239
initial.commit09911bf2008-07-26 23:55:29240 in_progress_.clear();
[email protected]70850c72011-01-11 17:31:27241 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59242 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59243 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29244
[email protected]41f558fb2012-01-09 22:59:58245 // We'll have nothing more to report to the observers after this point.
246 observers_.Clear();
247
[email protected]6d0146c2011-08-04 19:13:04248 DCHECK(save_page_downloads_.empty());
249
initial.commit09911bf2008-07-26 23:55:29250 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53251 delegate_->Shutdown();
initial.commit09911bf2008-07-26 23:55:29252}
253
[email protected]5656f8a2011-11-17 16:12:58254void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04255 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57256 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58257
[email protected]f04182f32010-12-10 19:12:07258 for (DownloadMap::iterator it = history_downloads_.begin();
259 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50260 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20261 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57262 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58263 }
[email protected]6aa4a1c02010-01-15 18:49:58264}
265
[email protected]5656f8a2011-11-17 16:12:58266void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04267 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57268 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34269
[email protected]f04182f32010-12-10 19:12:07270 for (DownloadMap::iterator it = history_downloads_.begin();
271 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50272 if (!it->second->IsTemporary() &&
273 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57274 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34275 }
[email protected]8ddbd66a2010-05-21 16:38:34276}
277
[email protected]5656f8a2011-11-17 16:12:58278void DownloadManagerImpl::SearchDownloads(const string16& query,
279 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26280 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42281
[email protected]f04182f32010-12-10 19:12:07282 for (DownloadMap::iterator it = history_downloads_.begin();
283 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42284 DownloadItem* download_item = it->second;
285
[email protected]c09a8fd2011-11-21 19:54:50286 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42287 continue;
288
289 // Display Incognito downloads only in Incognito window, and vice versa.
290 // The Incognito Downloads page will get the list of non-Incognito downloads
291 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50292 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42293 continue;
294
295 if (download_item->MatchesQuery(query_lower))
296 result->push_back(download_item);
297 }
[email protected]d3b12902010-08-16 23:39:42298}
299
initial.commit09911bf2008-07-26 23:55:29300// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58301bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03302 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29303 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
304 shutdown_needed_ = true;
305
[email protected]6d0c9fb2011-08-22 19:26:03306 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46307
[email protected]ea114722012-03-12 01:11:25308 // In test mode, there may be no ResourceDispatcherHostImpl. In this case
309 // it's safe to avoid setting |file_manager_| because we only call a small
310 // set of functions, none of which need it.
311 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
[email protected]b39e7a88b2012-01-10 21:43:17312 if (rdh) {
313 file_manager_ = rdh->download_file_manager();
314 DCHECK(file_manager_);
315 }
initial.commit09911bf2008-07-26 23:55:29316
initial.commit09911bf2008-07-26 23:55:29317 return true;
318}
319
[email protected]aa9881c2011-08-15 18:01:12320// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58321void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35323
[email protected]aa9881c2011-08-15 18:01:12324 if (delegate_->ShouldStartDownload(download_id))
325 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35326}
327
[email protected]5656f8a2011-11-17 16:12:58328void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
330 for (DownloadMap::iterator it = history_downloads_.begin();
331 it != history_downloads_.end(); ++it) {
332 CheckForFileRemoval(it->second);
333 }
334}
335
[email protected]5656f8a2011-11-17 16:12:58336void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50339 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48340 BrowserThread::PostTask(
341 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58342 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50343 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17344 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48345 }
346}
347
[email protected]5656f8a2011-11-17 16:12:58348void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48349 int64 db_handle, const FilePath& path) {
350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
351 if (!file_util::PathExists(path)) {
352 BrowserThread::PostTask(
353 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58354 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
355 this,
356 db_handle));
[email protected]9fc114672011-06-15 08:17:48357 }
358}
359
[email protected]5656f8a2011-11-17 16:12:58360void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
362 DownloadMap::iterator it = history_downloads_.find(db_handle);
363 if (it != history_downloads_.end()) {
364 DownloadItem* download_item = it->second;
365 download_item->OnDownloadedFileRemoved();
366 }
367}
368
[email protected]443853c62011-12-22 19:22:41369void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29371
[email protected]4cd82f72011-05-23 19:15:01372 DownloadItem* download = GetActiveDownloadItem(download_id);
373 if (!download)
374 return;
375
376 VLOG(20) << __FUNCTION__ << "()"
377 << " download = " << download->DebugString(true);
378
[email protected]c09a8fd2011-11-21 19:54:50379 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01380
[email protected]c09a8fd2011-11-21 19:54:50381 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29382 // We must ask the user for the place to put the download.
[email protected]a62d42902012-01-24 17:24:38383 WebContents* contents = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:26384
[email protected]795b76a2011-12-14 16:52:53385 FilePath target_path;
386 // If |download| is a potentially dangerous file, then |suggested_path|
387 // contains the intermediate name instead of the final download
388 // filename. The latter is GetTargetName().
[email protected]a62d42902012-01-24 17:24:38389 if (download->GetDangerType() !=
390 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
[email protected]795b76a2011-12-14 16:52:53391 target_path = suggested_path.DirName().Append(download->GetTargetName());
392 else
393 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26394
[email protected]795b76a2011-12-14 16:52:53395 delegate_->ChooseDownloadPath(contents, target_path,
[email protected]84d57412012-03-03 08:59:55396 download_id);
[email protected]f5920322011-03-24 20:34:16397 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]75e51b52012-02-04 16:57:54398 SelectFileDialogDisplayed(this, download_id));
initial.commit09911bf2008-07-26 23:55:29399 } else {
400 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01401 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29402 }
403}
404
[email protected]37757c62011-12-20 20:07:12405content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58406 return browser_context_;
407}
408
409FilePath DownloadManagerImpl::LastDownloadPath() {
410 return last_download_path_;
411}
412
[email protected]ef17c9a2012-02-09 05:08:09413net::BoundNetLog DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41414 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
416
[email protected]ef17c9a2012-02-09 05:08:09417 net::BoundNetLog bound_net_log =
418 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]c09a8fd2011-11-21 19:54:50419 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29420 this, *info, new DownloadRequestHandle(request_handle),
[email protected]ef17c9a2012-02-09 05:08:09421 browser_context_->IsOffTheRecord(), bound_net_log);
[email protected]2909e342011-10-29 00:46:53422 int32 download_id = info->download_id.local();
[email protected]4cd82f72011-05-23 19:15:01423 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]d8472d92011-08-26 20:15:20424
[email protected]0634626a2012-05-03 19:04:26425 DCHECK(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29426 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01427 active_downloads_[download_id] = download;
[email protected]ef17c9a2012-02-09 05:08:09428
429 return bound_net_log;
[email protected]c2e76012010-12-23 21:10:29430}
431
[email protected]fc03de22011-12-06 23:28:12432DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
433 const FilePath& main_file_path,
434 const GURL& page_url,
435 bool is_otr,
[email protected]6474b112012-05-04 19:35:27436 const std::string& mime_type,
[email protected]fc03de22011-12-06 23:28:12437 DownloadItem::Observer* observer) {
[email protected]ef17c9a2012-02-09 05:08:09438 net::BoundNetLog bound_net_log =
439 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12440 DownloadItem* download = new DownloadItemImpl(
[email protected]6474b112012-05-04 19:35:27441 this,
442 main_file_path,
443 page_url,
444 is_otr,
445 GetNextId(),
446 mime_type,
447 bound_net_log);
[email protected]fc03de22011-12-06 23:28:12448
449 download->AddObserver(observer);
450
451 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
452 downloads_.insert(download);
453 save_page_downloads_[download->GetId()] = download;
454
455 // Will notify the observer in the callback.
456 delegate_->AddItemToPersistentStore(download);
457
458 return download;
459}
460
[email protected]795b76a2011-12-14 16:52:53461// For non-safe downloads with no prompting, |chosen_file| is the intermediate
462// path for saving the in-progress download. The final target filename for these
463// is |download->GetTargetName()|. For all other downloads (non-safe downloads
464// for which we have prompted for a save location, and all safe downloads),
465// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58466void DownloadManagerImpl::ContinueDownloadWithPath(
467 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01469 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39470
[email protected]c09a8fd2011-11-21 19:54:50471 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29472
[email protected]70850c72011-01-11 17:31:27473 // NOTE(ahendrickson) Eventually |active_downloads_| will replace
474 // |in_progress_|, but we don't want to change the semantics yet.
[email protected]4cd82f72011-05-23 19:15:01475 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]70850c72011-01-11 17:31:27476 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01477 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27478
[email protected]4cd82f72011-05-23 19:15:01479 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20480 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01481 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01482
483 VLOG(20) << __FUNCTION__ << "()"
484 << " download = " << download->DebugString(true);
485
486 in_progress_[download_id] = download;
initial.commit09911bf2008-07-26 23:55:29487
[email protected]adb2f3d12011-01-23 16:24:54488 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16489 FilePath download_path;
[email protected]385e93182012-01-30 17:11:03490 if (download->GetDangerType() !=
491 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
492 if (download->PromptUserForSaveLocation()) {
493 // When we prompt the user, we overwrite the FullPath with what the user
494 // wanted to use. Construct a file path using the previously determined
495 // intermediate filename and the new path.
496 // TODO(asanka): This can trample an in-progress download in the new
497 // target directory if it was using the same intermediate name.
498 FilePath file_name = download->GetSuggestedPath().BaseName();
499 download_path = download->GetFullPath().DirName().Append(file_name);
500 } else {
501 // The download's name is already set to an intermediate name, so no need
502 // to override.
503 download_path = download->GetFullPath();
504 }
505 } else {
506 // The download is a safe download. We need to rename it to its
507 // intermediate path. The final name after user confirmation will be set
508 // from DownloadItem::OnDownloadCompleting.
509 download_path = delegate_->GetIntermediatePath(download->GetFullPath());
510 }
[email protected]594cd7d2010-07-21 03:23:56511
[email protected]f5920322011-03-24 20:34:16512 BrowserThread::PostTask(
513 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17514 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12515 file_manager_, download->GetGlobalId(),
516 download_path));
[email protected]f5920322011-03-24 20:34:16517
518 download->Rename(download_path);
519
[email protected]2588ea9d2011-08-22 20:59:53520 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29521}
522
[email protected]443853c62011-12-22 19:22:41523void DownloadManagerImpl::UpdateDownload(int32 download_id,
524 int64 bytes_so_far,
525 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00526 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
528 DownloadMap::iterator it = active_downloads_.find(download_id);
529 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29530 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26531 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41532 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]2588ea9d2011-08-22 20:59:53533 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27534 }
initial.commit09911bf2008-07-26 23:55:29535 }
536}
537
[email protected]5656f8a2011-11-17 16:12:58538void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
539 int64 size,
540 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54541 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50542 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
543 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35544 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32545
[email protected]c4f02c42011-01-24 21:55:06546 // If it's not in active_downloads_, that means it was cancelled; just
547 // ignore the notification.
548 if (active_downloads_.count(download_id) == 0)
549 return;
550
[email protected]adb2f3d12011-01-23 16:24:54551 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37552 download->OnAllDataSaved(size, hash);
[email protected]b09f1282011-09-14 00:37:45553
[email protected]fc03de22011-12-06 23:28:12554 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54555}
[email protected]9ccbb372008-10-10 18:50:32556
[email protected]fc03de22011-12-06 23:28:12557void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]c09a8fd2011-11-21 19:54:50558 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]0634626a2012-05-03 19:04:26559 DCHECK(!ContainsKey(downloads_, download));
560 DCHECK(!ContainsKey(active_downloads_, download->GetId()));
561 DCHECK(!ContainsKey(in_progress_, download->GetId()));
562 DCHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17563 return;
564 }
565
566 // Should be in downloads_ if we're not REMOVING.
567 CHECK(ContainsKey(downloads_, download));
568
569 // Check history_downloads_ consistency.
[email protected]5009b7a2012-02-21 18:47:03570 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50571 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17572 } else {
[email protected]fc03de22011-12-06 23:28:12573 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17574 it != history_downloads_.end(); ++it) {
[email protected]0634626a2012-05-03 19:04:26575 DCHECK(it->second != download);
[email protected]7d413112011-06-16 18:50:17576 }
577 }
578
[email protected]c09a8fd2011-11-21 19:54:50579 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34580 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50581 if (ContainsKey(active_downloads_, download->GetId())) {
[email protected]5009b7a2012-02-21 18:47:03582 if (download->IsPersisted())
[email protected]c09a8fd2011-11-21 19:54:50583 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
584 if (DownloadItem::IN_PROGRESS != download->GetState())
585 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07586 }
[email protected]c09a8fd2011-11-21 19:54:50587 if (DownloadItem::IN_PROGRESS == download->GetState())
588 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59589}
590
[email protected]5656f8a2011-11-17 16:12:58591bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54592 // If we don't have all the data, the download is not ready for
593 // completion.
[email protected]c09a8fd2011-11-21 19:54:50594 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54595 return false;
[email protected]6a7fb042010-02-01 16:30:47596
[email protected]9d7ef802011-02-25 19:03:35597 // If the download is dangerous, but not yet validated, it's not ready for
598 // completion.
[email protected]c09a8fd2011-11-21 19:54:50599 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35600 return false;
601
[email protected]adb2f3d12011-01-23 16:24:54602 // If the download isn't active (e.g. has been cancelled) it's not
603 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50604 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54605 return false;
606
607 // If the download hasn't been inserted into the history system
608 // (which occurs strictly after file name determination, intermediate
609 // file rename, and UI display) then it's not ready for completion.
[email protected]5009b7a2012-02-21 18:47:03610 if (!download->IsPersisted())
[email protected]7054b592011-06-22 14:46:42611 return false;
612
613 return true;
[email protected]adb2f3d12011-01-23 16:24:54614}
615
[email protected]6474b112012-05-04 19:35:27616// When SavePackage downloads MHTML to GData (see
617// SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
618// does for non-SavePackage downloads, but SavePackage downloads never satisfy
619// IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
620// DownloadItem::UpdateObservers() when the upload completes so that SavePackage
621// notices that the upload has completed and runs its normal Finish() pathway.
622// MaybeCompleteDownload() is never the mechanism by which SavePackage completes
623// downloads. SavePackage always uses its own Finish() to mark downloads
624// complete.
625
[email protected]5656f8a2011-11-17 16:12:58626void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54627 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
628 VLOG(20) << __FUNCTION__ << "()" << " download = "
629 << download->DebugString(false);
630
631 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32632 return;
[email protected]9ccbb372008-10-10 18:50:32633
[email protected]adb2f3d12011-01-23 16:24:54634 // TODO(rdsmith): DCHECK that we only pass through this point
635 // once per download. The natural way to do this is by a state
636 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56637
[email protected]adb2f3d12011-01-23 16:24:54638 // Confirm we're in the proper set of states to be here;
[email protected]9d7ef802011-02-25 19:03:35639 // in in_progress_, have all data, have a history handle, (validated or safe).
[email protected]c09a8fd2011-11-21 19:54:50640 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
641 DCHECK_EQ(1u, in_progress_.count(download->GetId()));
642 DCHECK(download->AllDataSaved());
[email protected]5009b7a2012-02-21 18:47:03643 DCHECK(download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50644 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54645
[email protected]c2918652011-11-01 18:50:23646 // Give the delegate a chance to override.
647 if (!delegate_->ShouldCompleteDownload(download))
648 return;
649
[email protected]adb2f3d12011-01-23 16:24:54650 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
651 << download->DebugString(false);
652
653 // Remove the id from in_progress
[email protected]c09a8fd2011-11-21 19:54:50654 in_progress_.erase(download->GetId());
[email protected]adb2f3d12011-01-23 16:24:54655
[email protected]2588ea9d2011-08-22 20:59:53656 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54657
[email protected]f5920322011-03-24 20:34:16658 // Finish the download.
[email protected]48837962011-04-19 17:03:29659 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32660}
661
[email protected]fc03de22011-12-06 23:28:12662void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27663 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21664 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53665 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12666 active_downloads_.erase(download->GetId());
667 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27668}
669
[email protected]5656f8a2011-11-17 16:12:58670void DownloadManagerImpl::OnDownloadRenamedToFinalName(
671 int download_id,
672 const FilePath& full_path,
673 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50674 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16675 << " full_path = \"" << full_path.value() << "\""
676 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18677 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16678
[email protected]2e030682010-07-23 19:45:36679 DownloadItem* item = GetDownloadItem(download_id);
680 if (!item)
681 return;
[email protected]6cade212008-12-03 00:32:22682
[email protected]a62d42902012-01-24 17:24:38683 if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
[email protected]795b76a2011-12-14 16:52:53684 item->PromptUserForSaveLocation()) {
685 DCHECK_EQ(0, uniquifier)
686 << "We should not uniquify user supplied filenames or safe filenames "
687 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02688 }
689
[email protected]fabf36d22011-10-28 21:50:17690 BrowserThread::PostTask(
691 BrowserThread::FILE, FROM_HERE,
692 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50693 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32694
[email protected]f5920322011-03-24 20:34:16695 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50696 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32697
[email protected]f5920322011-03-24 20:34:16698 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53699 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29700}
701
[email protected]5656f8a2011-11-17 16:12:58702void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17703 DownloadItem* download = GetActiveDownload(download_id);
704 // A cancel at the right time could remove the download from the
705 // |active_downloads_| map before we get here.
706 if (!download)
707 return;
708
709 download->Cancel(true);
710}
711
[email protected]fc03de22011-12-06 23:28:12712void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20713 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20714
715 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50716 << " download = " << download->DebugString(true);
717
[email protected]93af2272011-09-21 18:29:17718 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21719 // This function is called from the DownloadItem, so DI state
720 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12721 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29722
[email protected]15d90ba2011-11-03 03:41:55723 if (file_manager_)
724 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29725}
726
[email protected]bf3b08a2012-03-08 01:52:34727void DownloadManagerImpl::OnDownloadInterrupted(
728 int32 download_id,
729 int64 size,
730 const std::string& hash_state,
731 content::DownloadInterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21732 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
733
734 DownloadItem* download = GetActiveDownload(download_id);
735 if (!download)
736 return;
737
[email protected]be76b7e2011-10-13 12:57:57738 VLOG(20) << __FUNCTION__ << "()"
739 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50740 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21741 << " size = " << size
742 << " download = " << download->DebugString(true);
743
[email protected]93af2272011-09-21 18:29:17744 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41745 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17746 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21747}
748
[email protected]5656f8a2011-11-17 16:12:58749DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26750 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
751 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26752 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21753 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26754
755 DownloadItem* download = it->second;
756
[email protected]47a881b2011-08-29 22:59:21757 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50758 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01759
[email protected]47a881b2011-08-29 22:59:21760 return download;
761}
[email protected]54610672011-07-18 18:24:43762
[email protected]5656f8a2011-11-17 16:12:58763void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17764 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
765 DCHECK(download);
766
767 // Clean up will happen when the history system create callback runs if we
768 // don't have a valid db_handle yet.
[email protected]5009b7a2012-02-21 18:47:03769 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50770 in_progress_.erase(download->GetId());
771 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17772 delegate_->UpdateItemInPersistentStore(download);
773 }
774}
775
[email protected]fd3a82832012-01-19 20:35:12776bool DownloadManagerImpl::GenerateFileHash() {
777 return delegate_->GenerateFileHash();
778}
779
[email protected]5656f8a2011-11-17 16:12:58780content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
781 return delegate_;
782}
783
784void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17785 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35786 delegate_ = delegate;
787}
788
[email protected]5656f8a2011-11-17 16:12:58789int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04790 const DownloadVector& pending_deletes) {
791 if (pending_deletes.empty())
792 return 0;
793
794 // Delete from internal maps.
795 for (DownloadVector::const_iterator it = pending_deletes.begin();
796 it != pending_deletes.end();
797 ++it) {
798 DownloadItem* download = *it;
799 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50800 history_downloads_.erase(download->GetDbHandle());
801 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04802 downloads_.erase(download);
803 }
804
805 // Tell observers to refresh their views.
806 NotifyModelChanged();
807
808 // Delete the download items themselves.
809 const int num_deleted = static_cast<int>(pending_deletes.size());
810 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
811 return num_deleted;
812}
813
[email protected]fc03de22011-12-06 23:28:12814void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
815 if (history_downloads_.find(download->GetDbHandle()) ==
816 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17817 return;
818
819 // Make history update.
[email protected]93af2272011-09-21 18:29:17820 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29821
822 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04823 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07824 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29825}
826
[email protected]fd3a82832012-01-19 20:35:12827int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
828 base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53829 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29830
[email protected]a312a442010-12-15 23:40:33831 // All downloads visible to the user will be in the history,
832 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04833 DownloadVector pending_deletes;
834 for (DownloadMap::const_iterator it = history_downloads_.begin();
835 it != history_downloads_.end();
836 ++it) {
initial.commit09911bf2008-07-26 23:55:29837 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50838 if (download->GetStartTime() >= remove_begin &&
839 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04840 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12841 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28842 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29843 }
initial.commit09911bf2008-07-26 23:55:29844 }
[email protected]6d0146c2011-08-04 19:13:04845 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29846}
847
[email protected]fd3a82832012-01-19 20:35:12848int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59849 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29850}
851
[email protected]5656f8a2011-11-17 16:12:58852int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06853 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12854 // The null times make the date range unbounded.
855 return RemoveDownloadsBetween(base::Time(), base::Time());
856}
857
initial.commit09911bf2008-07-26 23:55:29858// Initiate a download of a specific URL. We send the request to the
859// ResourceDispatcherHost, and let it send us responses like a regular
860// download.
[email protected]0d4e30c2012-01-28 00:47:53861void DownloadManagerImpl::DownloadUrl(
862 const GURL& url,
863 const GURL& referrer,
864 const std::string& referrer_charset,
865 bool prefer_cache,
[email protected]27678b2a2012-02-04 22:09:14866 int64 post_id,
[email protected]29a5ffc82012-03-13 19:35:58867 const content::DownloadSaveInfo& save_info,
[email protected]89e6aa72012-03-12 22:51:33868 WebContents* web_contents,
869 const OnStartedCallback& callback) {
[email protected]ea114722012-03-12 01:11:25870 ResourceDispatcherHostImpl* resource_dispatcher_host =
871 ResourceDispatcherHostImpl::Get();
872 DCHECK(resource_dispatcher_host);
[email protected]443853c62011-12-22 19:22:41873
[email protected]ed24fad2011-05-10 22:44:01874 // We send a pointer to content::ResourceContext, instead of the usual
875 // reference, so that a copy of the object isn't made.
[email protected]fabf36d22011-10-28 21:50:17876 // base::Bind can't handle 7 args, so we use URLParams and RenderParams.
877 BrowserThread::PostTask(
878 BrowserThread::IO, FROM_HERE,
[email protected]0d4e30c2012-01-28 00:47:53879 base::Bind(
880 &BeginDownload,
[email protected]89e6aa72012-03-12 22:51:33881 URLParams(url, referrer, post_id, prefer_cache),
[email protected]0d4e30c2012-01-28 00:47:53882 save_info,
883 resource_dispatcher_host,
[email protected]fbc5e5f92012-01-02 06:08:32884 RenderParams(web_contents->GetRenderProcessHost()->GetID(),
[email protected]9f76c1e2012-03-05 15:15:58885 web_contents->GetRenderViewHost()->GetRoutingID()),
[email protected]89e6aa72012-03-12 22:51:33886 web_contents->GetBrowserContext()->GetResourceContext(),
887 callback));
initial.commit09911bf2008-07-26 23:55:29888}
889
[email protected]5656f8a2011-11-17 16:12:58890void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29891 observers_.AddObserver(observer);
[email protected]a1e41e72012-02-22 17:41:25892 // TODO: It is the responsibility of the observers to query the
893 // DownloadManager. Remove the following call from here and update all
894 // observers.
[email protected]75e51b52012-02-04 16:57:54895 observer->ModelChanged(this);
initial.commit09911bf2008-07-26 23:55:29896}
897
[email protected]5656f8a2011-11-17 16:12:58898void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29899 observers_.RemoveObserver(observer);
900}
901
[email protected]84d57412012-03-03 08:59:55902void DownloadManagerImpl::FileSelected(const FilePath& path,
903 int32 download_id) {
[email protected]4cd82f72011-05-23 19:15:01904 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
905
[email protected]4cd82f72011-05-23 19:15:01906 DownloadItem* download = GetActiveDownloadItem(download_id);
907 if (!download)
908 return;
909 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
910 << " download = " << download->DebugString(true);
911
[email protected]71f55842012-03-24 04:09:02912 // Retain the last directory that was picked by the user. Exclude temporary
913 // downloads since the path likely points at the location of a temporary file.
914 if (download->PromptUserForSaveLocation() && !download->IsTemporary())
[email protected]7ae7c2cb2009-01-06 23:31:41915 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35916
[email protected]4cd82f72011-05-23 19:15:01917 // Make sure the initial file name is set only once.
918 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29919}
920
[email protected]84d57412012-03-03 08:59:55921void DownloadManagerImpl::FileSelectionCanceled(int32 download_id) {
initial.commit09911bf2008-07-26 23:55:29922 // The user didn't pick a place to save the file, so need to cancel the
923 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01924 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01925
926 DownloadItem* download = GetActiveDownloadItem(download_id);
927 if (!download)
928 return;
929
930 VLOG(20) << __FUNCTION__ << "()"
931 << " download = " << download->DebugString(true);
932
[email protected]8f8bc112012-02-22 12:36:31933 download->Cancel(true);
[email protected]4cd82f72011-05-23 19:15:01934}
935
initial.commit09911bf2008-07-26 23:55:29936// Operations posted to us from the history service ----------------------------
937
938// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25939// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58940void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25941 std::vector<DownloadPersistentStoreInfo>* entries) {
initial.commit09911bf2008-07-26 23:55:29942 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]deb40832012-02-23 15:41:37943 int64 db_handle = entries->at(i).db_handle;
944 base::debug::Alias(&db_handle);
[email protected]0634626a2012-05-03 19:04:26945 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]deb40832012-02-23 15:41:37946
[email protected]ef17c9a2012-02-09 05:08:09947 net::BoundNetLog bound_net_log =
948 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12949 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09950 this, GetNextId(), entries->at(i), bound_net_log);
[email protected]f04182f32010-12-10 19:12:07951 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50952 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50953 VLOG(20) << __FUNCTION__ << "()" << i << ">"
954 << " download = " << download->DebugString(true);
initial.commit09911bf2008-07-26 23:55:29955 }
[email protected]b0ab1d42010-02-24 19:29:28956 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48957 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29958}
959
[email protected]5656f8a2011-11-17 16:12:58960void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
961 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27962 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]0634626a2012-05-03 19:04:26963 DCHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33964
[email protected]da4a5582011-10-17 19:08:06965 download_stats::RecordHistorySize(history_downloads_.size());
966
[email protected]5009b7a2012-02-21 18:47:03967 DCHECK(!download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50968 download->SetDbHandle(db_handle);
[email protected]5009b7a2012-02-21 18:47:03969 download->SetIsPersisted();
[email protected]5bcd73eb2011-03-23 21:14:02970
[email protected]0634626a2012-05-03 19:04:26971 DCHECK(!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]e5107ce2011-09-19 20:36:131007 int32 matching_item_download_id
1008 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:501009 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:131010 base::debug::Alias(&matching_item_download_id);
1011
[email protected]0634626a2012-05-03 19:04:261012 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201013
[email protected]f9a45b02011-06-30 23:49:191014 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:291015
[email protected]93af2272011-09-21 18:29:171016 // If the download is still in progress, try to complete it.
1017 //
1018 // Otherwise, download has been cancelled or interrupted before we've
1019 // received the DB handle. We post one final message to the history
1020 // service so that it can be properly in sync with the DownloadItem's
1021 // completion status, and also inform any observers so that they get
1022 // more than just the start notification.
1023 if (download->IsInProgress()) {
1024 MaybeCompleteDownload(download);
1025 } else {
[email protected]0634626a2012-05-03 19:04:261026 DCHECK(download->IsCancelled());
[email protected]93af2272011-09-21 18:29:171027 in_progress_.erase(download_id);
1028 active_downloads_.erase(download_id);
1029 delegate_->UpdateItemInPersistentStore(download);
1030 download->UpdateObservers();
1031 }
initial.commit09911bf2008-07-26 23:55:291032}
1033
[email protected]5656f8a2011-11-17 16:12:581034void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]a29e4f22012-04-12 21:22:031035 // The 'contents' may no longer exist if the user closed the contents before
1036 // we get this start completion event.
[email protected]a62d42902012-01-24 17:24:381037 WebContents* content = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:261038
1039 // If the contents no longer exists, we ask the embedder to suggest another
[email protected]a29e4f22012-04-12 21:22:031040 // contents.
[email protected]da1a27b2011-07-29 23:16:331041 if (!content)
[email protected]ef9572e2012-01-04 22:14:121042 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:531043
[email protected]0bfbf882011-12-22 18:19:271044 if (content && content->GetDelegate())
1045 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531046}
1047
[email protected]5656f8a2011-11-17 16:12:581048int DownloadManagerImpl::InProgressCount() const {
[email protected]007e7412012-03-13 20:10:561049 // Don't use in_progress_.count() because Cancel() leaves items in
1050 // in_progress_ if they haven't made it into the persistent store yet.
1051 // Need to actually look at each item's state.
1052 int count = 0;
1053 for (DownloadMap::const_iterator it = in_progress_.begin();
1054 it != in_progress_.end(); ++it) {
1055 DownloadItem* item = it->second;
1056 if (item->IsInProgress())
1057 ++count;
1058 }
1059 return count;
[email protected]5656f8a2011-11-17 16:12:581060}
1061
[email protected]6cade212008-12-03 00:32:221062// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581063void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411064 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381065}
[email protected]b0ab1d42010-02-24 19:29:281066
[email protected]5656f8a2011-11-17 16:12:581067void DownloadManagerImpl::NotifyModelChanged() {
[email protected]75e51b52012-02-04 16:57:541068 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged(this));
[email protected]b0ab1d42010-02-24 19:29:281069}
1070
[email protected]5656f8a2011-11-17 16:12:581071DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011072 // The |history_downloads_| map is indexed by the download's db_handle,
1073 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071074 for (DownloadMap::iterator it = history_downloads_.begin();
1075 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361076 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501077 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361078 return item;
1079 }
1080 return NULL;
1081}
1082
[email protected]5656f8a2011-11-17 16:12:581083DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361084 if (ContainsKey(active_downloads_, download_id))
1085 return active_downloads_[download_id];
1086 return NULL;
[email protected]4cd82f72011-05-23 19:15:011087}
1088
[email protected]57fd1252010-12-23 17:24:091089// Confirm that everything in all maps is also in |downloads_|, and that
1090// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581091void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071092#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091093 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041094 const DownloadMap* input_maps[] = {&active_downloads_,
1095 &history_downloads_,
1096 &save_page_downloads_};
1097 DownloadSet active_set, history_set, save_page_set;
1098 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1099 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091100 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1101 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041102 it != input_maps[i]->end(); ++it) {
1103 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071104 }
1105 }
[email protected]57fd1252010-12-23 17:24:091106
1107 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091108 DownloadSet downloads_union;
1109 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1110 DownloadSet remainder;
1111 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1112 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1113 downloads_.begin(), downloads_.end(),
1114 insert_it);
1115 DCHECK(remainder.empty());
1116 std::insert_iterator<DownloadSet>
1117 insert_union(downloads_union, downloads_union.end());
1118 std::set_union(downloads_union.begin(), downloads_union.end(),
1119 all_sets[i]->begin(), all_sets[i]->end(),
1120 insert_union);
1121 }
1122
1123 // Is everything in downloads_ present in one of the other sets?
1124 DownloadSet remainder;
1125 std::insert_iterator<DownloadSet>
1126 insert_remainder(remainder, remainder.begin());
1127 std::set_difference(downloads_.begin(), downloads_.end(),
1128 downloads_union.begin(), downloads_union.end(),
1129 insert_remainder);
1130 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071131#endif
1132}
1133
[email protected]6d0146c2011-08-04 19:13:041134// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531135// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041136// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531137// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1138// that the history event is update regardless of the order in which these two
1139// events complete.
[email protected]6d0146c2011-08-04 19:13:041140// If something removes the download item from the download manager (Remove,
1141// Shutdown) the result will be that the SavePage system will not be able to
1142// properly update the download item (which no longer exists) or the download
1143// history, but the action will complete properly anyway. This may lead to the
1144// history entry being wrong on a reload of chrome (specifically in the case of
1145// Initiation -> History Callback -> Removal -> Completion), but there's no way
1146// to solve that without canceling on Remove (which would then update the DB).
1147
[email protected]5656f8a2011-11-17 16:12:581148void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1149 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1151
1152 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1153 // This can happen if the download manager is shutting down and all maps
1154 // have been cleared.
1155 if (it == save_page_downloads_.end())
1156 return;
1157
1158 DownloadItem* download = it->second;
1159 if (!download) {
1160 NOTREACHED();
1161 return;
1162 }
1163
[email protected]0634626a2012-05-03 19:04:261164 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201165
[email protected]6d0146c2011-08-04 19:13:041166 AddDownloadItemToHistory(download, db_handle);
1167
1168 // Finalize this download if it finished before the history callback.
1169 if (!download->IsInProgress())
1170 SavePageDownloadFinished(download);
1171}
1172
[email protected]5656f8a2011-11-17 16:12:581173void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]5009b7a2012-02-21 18:47:031174 if (download->IsPersisted()) {
[email protected]2588ea9d2011-08-22 20:59:531175 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501176 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1177 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041178
1179 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071180 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041181 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531182 content::Source<DownloadManager>(this),
1183 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041184 }
1185}
[email protected]da4a5582011-10-17 19:08:061186
[email protected]fc03de22011-12-06 23:28:121187void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061188 delegate_->UpdateItemInPersistentStore(download);
1189 int num_unopened = 0;
1190 for (DownloadMap::iterator it = history_downloads_.begin();
1191 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501192 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061193 ++num_unopened;
1194 }
1195 download_stats::RecordOpensOutstanding(num_unopened);
1196}
[email protected]5656f8a2011-11-17 16:12:581197
[email protected]5948e1a2012-03-10 00:19:181198void DownloadManagerImpl::SetFileManagerForTesting(
1199 DownloadFileManager* file_manager) {
[email protected]5656f8a2011-11-17 16:12:581200 file_manager_ = file_manager;
1201}