blob: 82c61e3f8044f785fe3e9ce5c813f937428e23bf [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]2909e342011-10-29 00:46:5322#include "content/browser/download/download_id_factory.h"
[email protected]c09a8fd2011-11-21 19:54:5023#include "content/browser/download/download_item_impl.h"
[email protected]bb1a4212011-08-22 22:38:2524#include "content/browser/download/download_persistent_store_info.h"
[email protected]da4a5582011-10-17 19:08:0625#include "content/browser/download/download_stats.h"
[email protected]71bf3f5e2011-08-15 21:05:2226#include "content/browser/download/download_status_updater.h"
[email protected]be76b7e2011-10-13 12:57:5727#include "content/browser/download/interrupt_reasons.h"
[email protected]7324d1d2011-03-01 05:02:1628#include "content/browser/renderer_host/render_view_host.h"
29#include "content/browser/renderer_host/resource_dispatcher_host.h"
30#include "content/browser/tab_contents/tab_contents.h"
[email protected]ccb797302011-12-15 16:55:1131#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4932#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4433#include "content/public/browser/content_browser_client.h"
[email protected]1bd0ef12011-10-20 05:24:1734#include "content/public/browser/download_manager_delegate.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]e582fdd2011-12-20 16:48:1751using content::DownloadItem;
[email protected]2a6bc3e2011-12-28 23:51:3352using content::WebContents;
[email protected]631bb742011-11-02 11:29:3953
[email protected]a0ce3282011-08-19 20:49:5254namespace {
55
[email protected]fabf36d22011-10-28 21:50:1756// Param structs exist because base::Bind can only handle 6 args.
57struct URLParams {
58 URLParams(const GURL& url, const GURL& referrer)
59 : url_(url), referrer_(referrer) {}
60 GURL url_;
61 GURL referrer_;
62};
63
64struct RenderParams {
65 RenderParams(int rpi, int rvi)
66 : render_process_id_(rpi), render_view_id_(rvi) {}
67 int render_process_id_;
68 int render_view_id_;
69};
70
71void BeginDownload(const URLParams& url_params,
72 const DownloadSaveInfo& save_info,
73 ResourceDispatcherHost* resource_dispatcher_host,
74 const RenderParams& render_params,
75 const content::ResourceContext* context) {
[email protected]c1ba99842012-01-19 20:56:0576 scoped_ptr<net::URLRequest> request(
77 new net::URLRequest(url_params.url_, resource_dispatcher_host));
[email protected]fabf36d22011-10-28 21:50:1778 request->set_referrer(url_params.referrer_.spec());
[email protected]c79a0c02011-08-22 22:37:3779 resource_dispatcher_host->BeginDownload(
[email protected]c1ba99842012-01-19 20:56:0580 request.Pass(), save_info, true,
[email protected]8e3ae68c2011-09-16 22:15:4781 DownloadResourceHandler::OnStartedCallback(),
[email protected]fabf36d22011-10-28 21:50:1782 render_params.render_process_id_,
83 render_params.render_view_id_,
[email protected]c79a0c02011-08-22 22:37:3784 *context);
[email protected]a0ce3282011-08-19 20:49:5285}
86
87} // namespace
88
[email protected]99907362012-01-11 05:41:4089namespace content {
90
91// static
92DownloadManager* DownloadManager::Create(
93 content::DownloadManagerDelegate* delegate,
94 DownloadIdFactory* id_factory,
95 DownloadStatusUpdater* status_updater) {
96 return new DownloadManagerImpl(delegate, id_factory, status_updater);
97}
98
99} // namespace content
100
[email protected]5656f8a2011-11-17 16:12:58101DownloadManagerImpl::DownloadManagerImpl(
102 content::DownloadManagerDelegate* delegate,
103 DownloadIdFactory* id_factory,
104 DownloadStatusUpdater* status_updater)
105 : shutdown_needed_(false),
106 browser_context_(NULL),
107 file_manager_(NULL),
108 status_updater_((status_updater != NULL)
109 ? status_updater->AsWeakPtr()
110 : base::WeakPtr<DownloadStatusUpdater>()),
111 delegate_(delegate),
112 id_factory_(id_factory),
113 largest_db_handle_in_history_(DownloadItem::kUninitializedHandle) {
[email protected]eda58402011-09-21 19:32:02114 // NOTE(benjhayden): status_updater may be NULL when using
115 // TestingBrowserProcess.
116 if (status_updater_.get() != NULL)
[email protected]073ed7b2010-09-27 09:20:02117 status_updater_->AddDelegate(this);
initial.commit09911bf2008-07-26 23:55:29118}
119
[email protected]5656f8a2011-11-17 16:12:58120DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13121 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29122}
123
[email protected]5656f8a2011-11-17 16:12:58124DownloadId DownloadManagerImpl::GetNextId() {
[email protected]2909e342011-10-29 00:46:53125 return id_factory_->GetNextId();
126}
127
[email protected]fc03de22011-12-06 23:28:12128bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
129 return delegate_->ShouldOpenDownload(item);
130}
131
132bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
133 return delegate_->ShouldOpenFileBasedOnExtension(path);
134}
135
[email protected]5656f8a2011-11-17 16:12:58136void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50137 VLOG(20) << __FUNCTION__ << "()"
138 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13139 if (!shutdown_needed_)
140 return;
141 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29142
[email protected]326a6a92010-09-10 20:21:13143 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown());
[email protected]fb4f8d902011-09-16 06:07:08144 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13145
146 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18147 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17148 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
149 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13150 }
initial.commit09911bf2008-07-26 23:55:29151
[email protected]f04182f32010-12-10 19:12:07152 AssertContainersConsistent();
153
154 // Go through all downloads in downloads_. Dangerous ones we need to
155 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09156 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07157 DownloadItem* download = *it;
158
159 // Save iterator from potential erases in this set done by called code.
160 // Iterators after an erasure point are still valid for lists and
161 // associative containers such as sets.
162 it++;
163
[email protected]c09a8fd2011-11-21 19:54:50164 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29165 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07166 // The user hasn't accepted it, so we need to remove it
167 // from the disk. This may or may not result in it being
168 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12169 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07170 // removes and deletes it if it's known to the history service)
171 // so the only thing we know after calling this function is that
172 // the download was deleted if-and-only-if it was removed
173 // from all queues.
[email protected]303077002011-04-19 23:21:01174 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26175 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17176 download->Cancel(false);
177 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29178 }
179 }
180
[email protected]f04182f32010-12-10 19:12:07181 // At this point, all dangerous downloads have had their files removed
182 // and all in progress downloads have been cancelled. We can now delete
183 // anything left.
[email protected]9ccbb372008-10-10 18:50:32184
[email protected]5cd11b6e2011-06-10 20:30:59185 // Copy downloads_ to separate container so as not to set off checks
186 // in DownloadItem destruction.
187 DownloadSet downloads_to_delete;
188 downloads_to_delete.swap(downloads_);
189
initial.commit09911bf2008-07-26 23:55:29190 in_progress_.clear();
[email protected]70850c72011-01-11 17:31:27191 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59192 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59193 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29194
[email protected]41f558fb2012-01-09 22:59:58195 // We'll have nothing more to report to the observers after this point.
196 observers_.Clear();
197
[email protected]6d0146c2011-08-04 19:13:04198 DCHECK(save_page_downloads_.empty());
199
initial.commit09911bf2008-07-26 23:55:29200 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53201 delegate_->Shutdown();
[email protected]82f37b02010-07-29 22:04:57202
[email protected]41f558fb2012-01-09 22:59:58203 if (status_updater_)
204 status_updater_->RemoveDelegate(this);
205 status_updater_.reset();
initial.commit09911bf2008-07-26 23:55:29206}
207
[email protected]5656f8a2011-11-17 16:12:58208void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04209 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57210 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58211
[email protected]f04182f32010-12-10 19:12:07212 for (DownloadMap::iterator it = history_downloads_.begin();
213 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50214 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20215 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57216 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58217 }
[email protected]6aa4a1c02010-01-15 18:49:58218}
219
[email protected]5656f8a2011-11-17 16:12:58220void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04221 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57222 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34223
[email protected]f04182f32010-12-10 19:12:07224 for (DownloadMap::iterator it = history_downloads_.begin();
225 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50226 if (!it->second->IsTemporary() &&
227 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57228 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34229 }
[email protected]8ddbd66a2010-05-21 16:38:34230}
231
[email protected]5656f8a2011-11-17 16:12:58232void DownloadManagerImpl::SearchDownloads(const string16& query,
233 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26234 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42235
[email protected]f04182f32010-12-10 19:12:07236 for (DownloadMap::iterator it = history_downloads_.begin();
237 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42238 DownloadItem* download_item = it->second;
239
[email protected]c09a8fd2011-11-21 19:54:50240 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42241 continue;
242
243 // Display Incognito downloads only in Incognito window, and vice versa.
244 // The Incognito Downloads page will get the list of non-Incognito downloads
245 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50246 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42247 continue;
248
249 if (download_item->MatchesQuery(query_lower))
250 result->push_back(download_item);
251 }
[email protected]d3b12902010-08-16 23:39:42252}
253
initial.commit09911bf2008-07-26 23:55:29254// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58255bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03256 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29257 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
258 shutdown_needed_ = true;
259
[email protected]6d0c9fb2011-08-22 19:26:03260 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46261
[email protected]b39e7a88b2012-01-10 21:43:17262 // In test mode, there may be no ResourceDispatcherHost. In this case it's
263 // safe to avoid setting |file_manager_| because we only call a small set of
264 // functions, none of which need it.
[email protected]99907362012-01-11 05:41:40265 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get();
[email protected]b39e7a88b2012-01-10 21:43:17266 if (rdh) {
267 file_manager_ = rdh->download_file_manager();
268 DCHECK(file_manager_);
269 }
initial.commit09911bf2008-07-26 23:55:29270
initial.commit09911bf2008-07-26 23:55:29271 return true;
272}
273
[email protected]aa9881c2011-08-15 18:01:12274// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58275void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35277
[email protected]aa9881c2011-08-15 18:01:12278 if (delegate_->ShouldStartDownload(download_id))
279 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35280}
281
[email protected]5656f8a2011-11-17 16:12:58282void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
284 for (DownloadMap::iterator it = history_downloads_.begin();
285 it != history_downloads_.end(); ++it) {
286 CheckForFileRemoval(it->second);
287 }
288}
289
[email protected]5656f8a2011-11-17 16:12:58290void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
292 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50293 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48294 BrowserThread::PostTask(
295 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58296 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50297 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17298 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48299 }
300}
301
[email protected]5656f8a2011-11-17 16:12:58302void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48303 int64 db_handle, const FilePath& path) {
304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
305 if (!file_util::PathExists(path)) {
306 BrowserThread::PostTask(
307 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58308 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
309 this,
310 db_handle));
[email protected]9fc114672011-06-15 08:17:48311 }
312}
313
[email protected]5656f8a2011-11-17 16:12:58314void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
316 DownloadMap::iterator it = history_downloads_.find(db_handle);
317 if (it != history_downloads_.end()) {
318 DownloadItem* download_item = it->second;
319 download_item->OnDownloadedFileRemoved();
320 }
321}
322
[email protected]443853c62011-12-22 19:22:41323void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29325
[email protected]4cd82f72011-05-23 19:15:01326 DownloadItem* download = GetActiveDownloadItem(download_id);
327 if (!download)
328 return;
329
330 VLOG(20) << __FUNCTION__ << "()"
331 << " download = " << download->DebugString(true);
332
[email protected]c09a8fd2011-11-21 19:54:50333 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01334
[email protected]c09a8fd2011-11-21 19:54:50335 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29336 // We must ask the user for the place to put the download.
[email protected]ef9572e2012-01-04 22:14:12337 WebContents* contents = download->GetTabContents();
[email protected]99cb7f82011-07-28 17:27:26338
[email protected]4cd82f72011-05-23 19:15:01339 // |id_ptr| will be deleted in either FileSelected() or
[email protected]93af2272011-09-21 18:29:17340 // FileSelectionCancelled().
[email protected]4cd82f72011-05-23 19:15:01341 int32* id_ptr = new int32;
342 *id_ptr = download_id;
[email protected]795b76a2011-12-14 16:52:53343 FilePath target_path;
344 // If |download| is a potentially dangerous file, then |suggested_path|
345 // contains the intermediate name instead of the final download
346 // filename. The latter is GetTargetName().
347 if (download->GetDangerType() != DownloadStateInfo::NOT_DANGEROUS)
348 target_path = suggested_path.DirName().Append(download->GetTargetName());
349 else
350 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26351
[email protected]795b76a2011-12-14 16:52:53352 delegate_->ChooseDownloadPath(contents, target_path,
353 reinterpret_cast<void*>(id_ptr));
[email protected]f5920322011-03-24 20:34:16354 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]fed38252011-07-08 17:26:50355 SelectFileDialogDisplayed(download_id));
initial.commit09911bf2008-07-26 23:55:29356 } else {
357 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01358 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29359 }
360}
361
[email protected]37757c62011-12-20 20:07:12362content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58363 return browser_context_;
364}
365
366FilePath DownloadManagerImpl::LastDownloadPath() {
367 return last_download_path_;
368}
369
370void DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41371 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
373
[email protected]c09a8fd2011-11-21 19:54:50374 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29375 this, *info, new DownloadRequestHandle(request_handle),
376 browser_context_->IsOffTheRecord());
[email protected]2909e342011-10-29 00:46:53377 int32 download_id = info->download_id.local();
[email protected]4cd82f72011-05-23 19:15:01378 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]d8472d92011-08-26 20:15:20379
[email protected]a896ce32012-01-09 22:04:07380 CHECK_96627(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29381 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01382 active_downloads_[download_id] = download;
[email protected]c2e76012010-12-23 21:10:29383}
384
[email protected]fc03de22011-12-06 23:28:12385DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
386 const FilePath& main_file_path,
387 const GURL& page_url,
388 bool is_otr,
389 DownloadItem::Observer* observer) {
390 DownloadItem* download = new DownloadItemImpl(
391 this, main_file_path, page_url, is_otr, GetNextId());
392
393 download->AddObserver(observer);
394
395 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
396 downloads_.insert(download);
397 save_page_downloads_[download->GetId()] = download;
398
399 // Will notify the observer in the callback.
400 delegate_->AddItemToPersistentStore(download);
401
402 return download;
403}
404
[email protected]795b76a2011-12-14 16:52:53405// For non-safe downloads with no prompting, |chosen_file| is the intermediate
406// path for saving the in-progress download. The final target filename for these
407// is |download->GetTargetName()|. For all other downloads (non-safe downloads
408// for which we have prompted for a save location, and all safe downloads),
409// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58410void DownloadManagerImpl::ContinueDownloadWithPath(
411 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01413 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39414
[email protected]c09a8fd2011-11-21 19:54:50415 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29416
[email protected]70850c72011-01-11 17:31:27417 // NOTE(ahendrickson) Eventually |active_downloads_| will replace
418 // |in_progress_|, but we don't want to change the semantics yet.
[email protected]4cd82f72011-05-23 19:15:01419 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]70850c72011-01-11 17:31:27420 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01421 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27422
[email protected]4cd82f72011-05-23 19:15:01423 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20424 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01425 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01426
427 VLOG(20) << __FUNCTION__ << "()"
428 << " download = " << download->DebugString(true);
429
430 in_progress_[download_id] = download;
[email protected]5f8589fe2011-08-17 20:58:39431 UpdateDownloadProgress(); // Reflect entry into in_progress_.
initial.commit09911bf2008-07-26 23:55:29432
[email protected]adb2f3d12011-01-23 16:24:54433 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16434 FilePath download_path;
[email protected]ec865262011-08-23 20:01:48435 if (!delegate_->OverrideIntermediatePath(download, &download_path))
[email protected]c09a8fd2011-11-21 19:54:50436 download_path = download->GetFullPath();
[email protected]594cd7d2010-07-21 03:23:56437
[email protected]f5920322011-03-24 20:34:16438 BrowserThread::PostTask(
439 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17440 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12441 file_manager_, download->GetGlobalId(),
442 download_path));
[email protected]f5920322011-03-24 20:34:16443
444 download->Rename(download_path);
445
[email protected]2588ea9d2011-08-22 20:59:53446 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29447}
448
[email protected]443853c62011-12-22 19:22:41449void DownloadManagerImpl::UpdateDownload(int32 download_id,
450 int64 bytes_so_far,
451 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00452 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27453 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
454 DownloadMap::iterator it = active_downloads_.find(download_id);
455 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29456 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26457 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41458 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]5f8589fe2011-08-17 20:58:39459 UpdateDownloadProgress(); // Reflect size updates.
[email protected]2588ea9d2011-08-22 20:59:53460 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27461 }
initial.commit09911bf2008-07-26 23:55:29462 }
463}
464
[email protected]5656f8a2011-11-17 16:12:58465void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
466 int64 size,
467 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50469 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
470 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32472
[email protected]c4f02c42011-01-24 21:55:06473 // If it's not in active_downloads_, that means it was cancelled; just
474 // ignore the notification.
475 if (active_downloads_.count(download_id) == 0)
476 return;
477
[email protected]adb2f3d12011-01-23 16:24:54478 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37479 download->OnAllDataSaved(size, hash);
480 delegate_->OnResponseCompleted(download);
[email protected]b09f1282011-09-14 00:37:45481
[email protected]fc03de22011-12-06 23:28:12482 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54483}
[email protected]9ccbb372008-10-10 18:50:32484
[email protected]fc03de22011-12-06 23:28:12485void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]a896ce32012-01-09 22:04:07486 // TODO(rdsmith): Change to DCHECK after http://crbug.com/96627 resolved.
[email protected]c09a8fd2011-11-21 19:54:50487 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]7d413112011-06-16 18:50:17488 CHECK(!ContainsKey(downloads_, download));
[email protected]c09a8fd2011-11-21 19:54:50489 CHECK(!ContainsKey(active_downloads_, download->GetId()));
490 CHECK(!ContainsKey(in_progress_, download->GetId()));
491 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17492 return;
493 }
494
495 // Should be in downloads_ if we're not REMOVING.
496 CHECK(ContainsKey(downloads_, download));
497
498 // Check history_downloads_ consistency.
[email protected]c09a8fd2011-11-21 19:54:50499 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
500 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17501 } else {
[email protected]fc03de22011-12-06 23:28:12502 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17503 it != history_downloads_.end(); ++it) {
[email protected]a896ce32012-01-09 22:04:07504 CHECK_96627(it->second != download);
[email protected]7d413112011-06-16 18:50:17505 }
506 }
507
[email protected]c09a8fd2011-11-21 19:54:50508 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34509 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50510 if (ContainsKey(active_downloads_, download->GetId())) {
511 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle)
512 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
513 if (DownloadItem::IN_PROGRESS != download->GetState())
514 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07515 }
[email protected]c09a8fd2011-11-21 19:54:50516 if (DownloadItem::IN_PROGRESS == download->GetState())
517 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59518}
519
[email protected]5656f8a2011-11-17 16:12:58520bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54521 // If we don't have all the data, the download is not ready for
522 // completion.
[email protected]c09a8fd2011-11-21 19:54:50523 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54524 return false;
[email protected]6a7fb042010-02-01 16:30:47525
[email protected]9d7ef802011-02-25 19:03:35526 // If the download is dangerous, but not yet validated, it's not ready for
527 // completion.
[email protected]c09a8fd2011-11-21 19:54:50528 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35529 return false;
530
[email protected]adb2f3d12011-01-23 16:24:54531 // If the download isn't active (e.g. has been cancelled) it's not
532 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50533 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54534 return false;
535
536 // If the download hasn't been inserted into the history system
537 // (which occurs strictly after file name determination, intermediate
538 // file rename, and UI display) then it's not ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50539 if (download->GetDbHandle() == DownloadItem::kUninitializedHandle)
[email protected]7054b592011-06-22 14:46:42540 return false;
541
542 return true;
[email protected]adb2f3d12011-01-23 16:24:54543}
544
[email protected]5656f8a2011-11-17 16:12:58545void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
547 VLOG(20) << __FUNCTION__ << "()" << " download = "
548 << download->DebugString(false);
549
550 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32551 return;
[email protected]9ccbb372008-10-10 18:50:32552
[email protected]adb2f3d12011-01-23 16:24:54553 // TODO(rdsmith): DCHECK that we only pass through this point
554 // once per download. The natural way to do this is by a state
555 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56556
[email protected]adb2f3d12011-01-23 16:24:54557 // Confirm we're in the proper set of states to be here;
[email protected]9d7ef802011-02-25 19:03:35558 // in in_progress_, have all data, have a history handle, (validated or safe).
[email protected]c09a8fd2011-11-21 19:54:50559 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
560 DCHECK_EQ(1u, in_progress_.count(download->GetId()));
561 DCHECK(download->AllDataSaved());
562 DCHECK(download->GetDbHandle() != DownloadItem::kUninitializedHandle);
563 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54564
[email protected]c2918652011-11-01 18:50:23565 // Give the delegate a chance to override.
566 if (!delegate_->ShouldCompleteDownload(download))
567 return;
568
[email protected]adb2f3d12011-01-23 16:24:54569 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
570 << download->DebugString(false);
571
572 // Remove the id from in_progress
[email protected]c09a8fd2011-11-21 19:54:50573 in_progress_.erase(download->GetId());
[email protected]5f8589fe2011-08-17 20:58:39574 UpdateDownloadProgress(); // Reflect removal from in_progress_.
[email protected]adb2f3d12011-01-23 16:24:54575
[email protected]2588ea9d2011-08-22 20:59:53576 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54577
[email protected]f5920322011-03-24 20:34:16578 // Finish the download.
[email protected]48837962011-04-19 17:03:29579 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32580}
581
[email protected]fc03de22011-12-06 23:28:12582void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21584 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53585 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12586 active_downloads_.erase(download->GetId());
587 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27588}
589
[email protected]5656f8a2011-11-17 16:12:58590void DownloadManagerImpl::OnDownloadRenamedToFinalName(
591 int download_id,
592 const FilePath& full_path,
593 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50594 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16595 << " full_path = \"" << full_path.value() << "\""
596 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16598
[email protected]2e030682010-07-23 19:45:36599 DownloadItem* item = GetDownloadItem(download_id);
600 if (!item)
601 return;
[email protected]6cade212008-12-03 00:32:22602
[email protected]795b76a2011-12-14 16:52:53603 if (item->GetDangerType() == DownloadStateInfo::NOT_DANGEROUS ||
604 item->PromptUserForSaveLocation()) {
605 DCHECK_EQ(0, uniquifier)
606 << "We should not uniquify user supplied filenames or safe filenames "
607 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02608 }
609
[email protected]fabf36d22011-10-28 21:50:17610 BrowserThread::PostTask(
611 BrowserThread::FILE, FROM_HERE,
612 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50613 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32614
[email protected]f5920322011-03-24 20:34:16615 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50616 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32617
[email protected]f5920322011-03-24 20:34:16618 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53619 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29620}
621
[email protected]5656f8a2011-11-17 16:12:58622void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17623 DownloadItem* download = GetActiveDownload(download_id);
624 // A cancel at the right time could remove the download from the
625 // |active_downloads_| map before we get here.
626 if (!download)
627 return;
628
629 download->Cancel(true);
630}
631
[email protected]fc03de22011-12-06 23:28:12632void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20633 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20634
635 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50636 << " download = " << download->DebugString(true);
637
[email protected]93af2272011-09-21 18:29:17638 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21639 // This function is called from the DownloadItem, so DI state
640 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12641 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29642
[email protected]15d90ba2011-11-03 03:41:55643 if (file_manager_)
644 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29645}
646
[email protected]5656f8a2011-11-17 16:12:58647void DownloadManagerImpl::OnDownloadInterrupted(int32 download_id,
648 int64 size,
[email protected]0afff032012-01-06 20:55:00649 const std::string& hash_state,
[email protected]5656f8a2011-11-17 16:12:58650 InterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
652
653 DownloadItem* download = GetActiveDownload(download_id);
654 if (!download)
655 return;
656
[email protected]be76b7e2011-10-13 12:57:57657 VLOG(20) << __FUNCTION__ << "()"
658 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50659 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21660 << " size = " << size
661 << " download = " << download->DebugString(true);
662
[email protected]93af2272011-09-21 18:29:17663 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41664 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17665 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21666}
667
[email protected]5656f8a2011-11-17 16:12:58668DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26669 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
670 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26671 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21672 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26673
674 DownloadItem* download = it->second;
675
[email protected]47a881b2011-08-29 22:59:21676 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50677 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01678
[email protected]47a881b2011-08-29 22:59:21679 return download;
680}
[email protected]54610672011-07-18 18:24:43681
[email protected]5656f8a2011-11-17 16:12:58682void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
684 DCHECK(download);
685
686 // Clean up will happen when the history system create callback runs if we
687 // don't have a valid db_handle yet.
[email protected]c09a8fd2011-11-21 19:54:50688 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
689 in_progress_.erase(download->GetId());
690 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17691 UpdateDownloadProgress(); // Reflect removal from in_progress_.
692 delegate_->UpdateItemInPersistentStore(download);
693 }
694}
695
[email protected]fd3a82832012-01-19 20:35:12696bool DownloadManagerImpl::GenerateFileHash() {
697 return delegate_->GenerateFileHash();
698}
699
[email protected]5656f8a2011-11-17 16:12:58700content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
701 return delegate_;
702}
703
704void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17705 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35706 delegate_ = delegate;
707}
708
[email protected]5656f8a2011-11-17 16:12:58709void DownloadManagerImpl::UpdateDownloadProgress() {
[email protected]5f8589fe2011-08-17 20:58:39710 delegate_->DownloadProgressUpdated();
[email protected]6a7fb042010-02-01 16:30:47711}
712
[email protected]5656f8a2011-11-17 16:12:58713int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04714 const DownloadVector& pending_deletes) {
715 if (pending_deletes.empty())
716 return 0;
717
718 // Delete from internal maps.
719 for (DownloadVector::const_iterator it = pending_deletes.begin();
720 it != pending_deletes.end();
721 ++it) {
722 DownloadItem* download = *it;
723 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50724 history_downloads_.erase(download->GetDbHandle());
725 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04726 downloads_.erase(download);
727 }
728
729 // Tell observers to refresh their views.
730 NotifyModelChanged();
731
732 // Delete the download items themselves.
733 const int num_deleted = static_cast<int>(pending_deletes.size());
734 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
735 return num_deleted;
736}
737
[email protected]fc03de22011-12-06 23:28:12738void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
739 if (history_downloads_.find(download->GetDbHandle()) ==
740 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17741 return;
742
743 // Make history update.
[email protected]93af2272011-09-21 18:29:17744 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29745
746 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04747 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07748 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29749}
750
[email protected]fd3a82832012-01-19 20:35:12751int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
752 base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53753 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29754
[email protected]a312a442010-12-15 23:40:33755 // All downloads visible to the user will be in the history,
756 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04757 DownloadVector pending_deletes;
758 for (DownloadMap::const_iterator it = history_downloads_.begin();
759 it != history_downloads_.end();
760 ++it) {
initial.commit09911bf2008-07-26 23:55:29761 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50762 if (download->GetStartTime() >= remove_begin &&
763 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04764 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12765 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28766 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29767 }
initial.commit09911bf2008-07-26 23:55:29768 }
[email protected]6d0146c2011-08-04 19:13:04769 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29770}
771
[email protected]fd3a82832012-01-19 20:35:12772int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59773 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29774}
775
[email protected]5656f8a2011-11-17 16:12:58776int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06777 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12778 // The null times make the date range unbounded.
779 return RemoveDownloadsBetween(base::Time(), base::Time());
780}
781
initial.commit09911bf2008-07-26 23:55:29782// Initiate a download of a specific URL. We send the request to the
783// ResourceDispatcherHost, and let it send us responses like a regular
784// download.
[email protected]5656f8a2011-11-17 16:12:58785void DownloadManagerImpl::DownloadUrl(const GURL& url,
786 const GURL& referrer,
787 const std::string& referrer_charset,
[email protected]bb81f382012-01-03 22:45:44788 WebContents* web_contents) {
[email protected]ae8945192010-07-20 16:56:26789 DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(),
[email protected]bb81f382012-01-03 22:45:44790 web_contents);
[email protected]6aa4a1c02010-01-15 18:49:58791}
792
[email protected]5656f8a2011-11-17 16:12:58793void DownloadManagerImpl::DownloadUrlToFile(const GURL& url,
794 const GURL& referrer,
795 const std::string& referrer_charset,
796 const DownloadSaveInfo& save_info,
[email protected]fbc5e5f92012-01-02 06:08:32797 WebContents* web_contents) {
[email protected]c79a0c02011-08-22 22:37:37798 ResourceDispatcherHost* resource_dispatcher_host =
[email protected]99907362012-01-11 05:41:40799 ResourceDispatcherHost::Get();
[email protected]443853c62011-12-22 19:22:41800
[email protected]ed24fad2011-05-10 22:44:01801 // We send a pointer to content::ResourceContext, instead of the usual
802 // reference, so that a copy of the object isn't made.
[email protected]fabf36d22011-10-28 21:50:17803 // base::Bind can't handle 7 args, so we use URLParams and RenderParams.
804 BrowserThread::PostTask(
805 BrowserThread::IO, FROM_HERE,
806 base::Bind(&BeginDownload,
807 URLParams(url, referrer), save_info, resource_dispatcher_host,
[email protected]fbc5e5f92012-01-02 06:08:32808 RenderParams(web_contents->GetRenderProcessHost()->GetID(),
809 web_contents->GetRenderViewHost()->routing_id()),
810 &web_contents->GetBrowserContext()->GetResourceContext()));
initial.commit09911bf2008-07-26 23:55:29811}
812
[email protected]5656f8a2011-11-17 16:12:58813void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29814 observers_.AddObserver(observer);
815 observer->ModelChanged();
816}
817
[email protected]5656f8a2011-11-17 16:12:58818void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29819 observers_.RemoveObserver(observer);
820}
821
[email protected]5656f8a2011-11-17 16:12:58822bool DownloadManagerImpl::IsDownloadProgressKnown() const {
[email protected]45f432e942011-10-25 18:17:22823 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02824 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50825 if (i->second->GetTotalBytes() <= 0)
[email protected]073ed7b2010-09-27 09:20:02826 return false;
827 }
828
829 return true;
830}
831
[email protected]5656f8a2011-11-17 16:12:58832int64 DownloadManagerImpl::GetInProgressDownloadCount() const {
[email protected]073ed7b2010-09-27 09:20:02833 return in_progress_.size();
834}
835
[email protected]5656f8a2011-11-17 16:12:58836int64 DownloadManagerImpl::GetReceivedDownloadBytes() const {
[email protected]073ed7b2010-09-27 09:20:02837 DCHECK(IsDownloadProgressKnown());
838 int64 received_bytes = 0;
[email protected]45f432e942011-10-25 18:17:22839 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02840 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50841 received_bytes += i->second->GetReceivedBytes();
[email protected]073ed7b2010-09-27 09:20:02842 }
843 return received_bytes;
844}
845
[email protected]5656f8a2011-11-17 16:12:58846int64 DownloadManagerImpl::GetTotalDownloadBytes() const {
[email protected]073ed7b2010-09-27 09:20:02847 DCHECK(IsDownloadProgressKnown());
848 int64 total_bytes = 0;
[email protected]45f432e942011-10-25 18:17:22849 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02850 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50851 total_bytes += i->second->GetTotalBytes();
[email protected]073ed7b2010-09-27 09:20:02852 }
853 return total_bytes;
854}
855
[email protected]5656f8a2011-11-17 16:12:58856void DownloadManagerImpl::FileSelected(const FilePath& path, void* params) {
[email protected]4cd82f72011-05-23 19:15:01857 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
858
859 int32* id_ptr = reinterpret_cast<int32*>(params);
860 DCHECK(id_ptr != NULL);
861 int32 download_id = *id_ptr;
862 delete id_ptr;
863
864 DownloadItem* download = GetActiveDownloadItem(download_id);
865 if (!download)
866 return;
867 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
868 << " download = " << download->DebugString(true);
869
[email protected]c09a8fd2011-11-21 19:54:50870 if (download->PromptUserForSaveLocation())
[email protected]7ae7c2cb2009-01-06 23:31:41871 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35872
[email protected]4cd82f72011-05-23 19:15:01873 // Make sure the initial file name is set only once.
874 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29875}
876
[email protected]5656f8a2011-11-17 16:12:58877void DownloadManagerImpl::FileSelectionCanceled(void* params) {
initial.commit09911bf2008-07-26 23:55:29878 // The user didn't pick a place to save the file, so need to cancel the
879 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01880 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
881 int32* id_ptr = reinterpret_cast<int32*>(params);
882 DCHECK(id_ptr != NULL);
883 int32 download_id = *id_ptr;
884 delete id_ptr;
885
886 DownloadItem* download = GetActiveDownloadItem(download_id);
887 if (!download)
888 return;
889
890 VLOG(20) << __FUNCTION__ << "()"
891 << " download = " << download->DebugString(true);
892
[email protected]93af2272011-09-21 18:29:17893 // TODO(ahendrickson) -- This currently has no effect, as the download is
894 // not put on the active list until the file selection is complete. Need
895 // to put it on the active list earlier in the process.
896 RemoveFromActiveList(download);
897
898 download->OffThreadCancel(file_manager_);
[email protected]4cd82f72011-05-23 19:15:01899}
900
initial.commit09911bf2008-07-26 23:55:29901// Operations posted to us from the history service ----------------------------
902
903// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25904// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58905void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25906 std::vector<DownloadPersistentStoreInfo>* entries) {
[email protected]d8472d92011-08-26 20:15:20907 // TODO(rdsmith): Remove this and related logic when
[email protected]a896ce32012-01-09 22:04:07908 // http://crbug.com/96627 is fixed.
[email protected]d8472d92011-08-26 20:15:20909 largest_db_handle_in_history_ = 0;
910
initial.commit09911bf2008-07-26 23:55:29911 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]fc03de22011-12-06 23:28:12912 DownloadItem* download = new DownloadItemImpl(
913 this, GetNextId(), entries->at(i));
[email protected]a896ce32012-01-09 22:04:07914 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]f04182f32010-12-10 19:12:07915 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50916 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50917 VLOG(20) << __FUNCTION__ << "()" << i << ">"
918 << " download = " << download->DebugString(true);
[email protected]d8472d92011-08-26 20:15:20919
[email protected]c09a8fd2011-11-21 19:54:50920 if (download->GetDbHandle() > largest_db_handle_in_history_)
921 largest_db_handle_in_history_ = download->GetDbHandle();
initial.commit09911bf2008-07-26 23:55:29922 }
[email protected]b0ab1d42010-02-24 19:29:28923 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48924 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29925}
926
[email protected]5656f8a2011-11-17 16:12:58927void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
928 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27929 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d2a8fb72010-01-21 05:31:42930
[email protected]a896ce32012-01-09 22:04:07931 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]1e9fe7ff2011-06-24 17:37:33932 // is fixed.
[email protected]2588ea9d2011-08-22 20:59:53933 CHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33934
[email protected]da4a5582011-10-17 19:08:06935 download_stats::RecordHistorySize(history_downloads_.size());
936
[email protected]c09a8fd2011-11-21 19:54:50937 DCHECK(download->GetDbHandle() == DownloadItem::kUninitializedHandle);
938 download->SetDbHandle(db_handle);
[email protected]5bcd73eb2011-03-23 21:14:02939
[email protected]a896ce32012-01-09 22:04:07940 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]d8472d92011-08-26 20:15:20941 // is fixed.
[email protected]a896ce32012-01-09 22:04:07942 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]c09a8fd2011-11-21 19:54:50943 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04944
945 // Show in the appropriate browser UI.
946 // This includes buttons to save or cancel, for a dangerous download.
947 ShowDownloadInBrowser(download);
948
949 // Inform interested objects about the new download.
950 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19951}
952
[email protected]2588ea9d2011-08-22 20:59:53953
[email protected]5656f8a2011-11-17 16:12:58954void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
955 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53956 if (save_page_downloads_.count(download_id)) {
957 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
958 } else if (active_downloads_.count(download_id)) {
959 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
960 }
961 // It's valid that we don't find a matching item, i.e. on shutdown.
962}
963
[email protected]f9a45b02011-06-30 23:49:19964// Once the new DownloadItem's creation info has been committed to the history
965// service, we associate the DownloadItem with the db handle, update our
966// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:58967void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
968 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:19969 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:45970 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:17971 if (!download)
[email protected]19420cc2011-07-18 17:43:45972 return;
[email protected]54610672011-07-18 18:24:43973
974 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
975 << " download_id = " << download_id
976 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:19977
[email protected]a896ce32012-01-09 22:04:07978 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:20979 int64 largest_handle = largest_db_handle_in_history_;
980 base::debug::Alias(&largest_handle);
[email protected]e5107ce2011-09-19 20:36:13981 int32 matching_item_download_id
982 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:50983 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:13984 base::debug::Alias(&matching_item_download_id);
985
[email protected]a896ce32012-01-09 22:04:07986 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:20987
[email protected]f9a45b02011-06-30 23:49:19988 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:29989
[email protected]93af2272011-09-21 18:29:17990 // If the download is still in progress, try to complete it.
991 //
992 // Otherwise, download has been cancelled or interrupted before we've
993 // received the DB handle. We post one final message to the history
994 // service so that it can be properly in sync with the DownloadItem's
995 // completion status, and also inform any observers so that they get
996 // more than just the start notification.
997 if (download->IsInProgress()) {
998 MaybeCompleteDownload(download);
999 } else {
[email protected]a896ce32012-01-09 22:04:071000 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]93af2272011-09-21 18:29:171001 // is fixed.
1002 CHECK(download->IsCancelled())
1003 << " download = " << download->DebugString(true);
1004 in_progress_.erase(download_id);
1005 active_downloads_.erase(download_id);
1006 delegate_->UpdateItemInPersistentStore(download);
1007 download->UpdateObservers();
1008 }
initial.commit09911bf2008-07-26 23:55:291009}
1010
[email protected]5656f8a2011-11-17 16:12:581011void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]8ddbd66a2010-05-21 16:38:341012 // The 'contents' may no longer exist if the user closed the tab before we
[email protected]99cb7f82011-07-28 17:27:261013 // get this start completion event.
[email protected]2a6bc3e2011-12-28 23:51:331014 WebContents* content = download->GetTabContents();
[email protected]99cb7f82011-07-28 17:27:261015
1016 // If the contents no longer exists, we ask the embedder to suggest another
1017 // tab.
[email protected]da1a27b2011-07-29 23:16:331018 if (!content)
[email protected]ef9572e2012-01-04 22:14:121019 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:531020
[email protected]0bfbf882011-12-22 18:19:271021 if (content && content->GetDelegate())
1022 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531023}
1024
[email protected]5656f8a2011-11-17 16:12:581025int DownloadManagerImpl::InProgressCount() const {
1026 return static_cast<int>(in_progress_.size());
1027}
1028
[email protected]6cade212008-12-03 00:32:221029// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581030void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411031 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381032}
[email protected]b0ab1d42010-02-24 19:29:281033
[email protected]5656f8a2011-11-17 16:12:581034void DownloadManagerImpl::NotifyModelChanged() {
[email protected]b0ab1d42010-02-24 19:29:281035 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged());
1036}
1037
[email protected]5656f8a2011-11-17 16:12:581038DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011039 // The |history_downloads_| map is indexed by the download's db_handle,
1040 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071041 for (DownloadMap::iterator it = history_downloads_.begin();
1042 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361043 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501044 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361045 return item;
1046 }
1047 return NULL;
1048}
1049
[email protected]5656f8a2011-11-17 16:12:581050DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361051 if (ContainsKey(active_downloads_, download_id))
1052 return active_downloads_[download_id];
1053 return NULL;
[email protected]4cd82f72011-05-23 19:15:011054}
1055
[email protected]57fd1252010-12-23 17:24:091056// Confirm that everything in all maps is also in |downloads_|, and that
1057// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581058void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071059#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091060 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041061 const DownloadMap* input_maps[] = {&active_downloads_,
1062 &history_downloads_,
1063 &save_page_downloads_};
1064 DownloadSet active_set, history_set, save_page_set;
1065 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1066 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091067 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1068 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041069 it != input_maps[i]->end(); ++it) {
1070 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071071 }
1072 }
[email protected]57fd1252010-12-23 17:24:091073
1074 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091075 DownloadSet downloads_union;
1076 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1077 DownloadSet remainder;
1078 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1079 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1080 downloads_.begin(), downloads_.end(),
1081 insert_it);
1082 DCHECK(remainder.empty());
1083 std::insert_iterator<DownloadSet>
1084 insert_union(downloads_union, downloads_union.end());
1085 std::set_union(downloads_union.begin(), downloads_union.end(),
1086 all_sets[i]->begin(), all_sets[i]->end(),
1087 insert_union);
1088 }
1089
1090 // Is everything in downloads_ present in one of the other sets?
1091 DownloadSet remainder;
1092 std::insert_iterator<DownloadSet>
1093 insert_remainder(remainder, remainder.begin());
1094 std::set_difference(downloads_.begin(), downloads_.end(),
1095 downloads_union.begin(), downloads_union.end(),
1096 insert_remainder);
1097 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071098#endif
1099}
1100
[email protected]6d0146c2011-08-04 19:13:041101// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531102// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041103// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531104// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1105// that the history event is update regardless of the order in which these two
1106// events complete.
[email protected]6d0146c2011-08-04 19:13:041107// If something removes the download item from the download manager (Remove,
1108// Shutdown) the result will be that the SavePage system will not be able to
1109// properly update the download item (which no longer exists) or the download
1110// history, but the action will complete properly anyway. This may lead to the
1111// history entry being wrong on a reload of chrome (specifically in the case of
1112// Initiation -> History Callback -> Removal -> Completion), but there's no way
1113// to solve that without canceling on Remove (which would then update the DB).
1114
[email protected]5656f8a2011-11-17 16:12:581115void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1116 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1118
1119 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1120 // This can happen if the download manager is shutting down and all maps
1121 // have been cleared.
1122 if (it == save_page_downloads_.end())
1123 return;
1124
1125 DownloadItem* download = it->second;
1126 if (!download) {
1127 NOTREACHED();
1128 return;
1129 }
1130
[email protected]a896ce32012-01-09 22:04:071131 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201132 int64 largest_handle = largest_db_handle_in_history_;
1133 base::debug::Alias(&largest_handle);
[email protected]a896ce32012-01-09 22:04:071134 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201135
[email protected]6d0146c2011-08-04 19:13:041136 AddDownloadItemToHistory(download, db_handle);
1137
1138 // Finalize this download if it finished before the history callback.
1139 if (!download->IsInProgress())
1140 SavePageDownloadFinished(download);
1141}
1142
[email protected]5656f8a2011-11-17 16:12:581143void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]c09a8fd2011-11-21 19:54:501144 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
[email protected]2588ea9d2011-08-22 20:59:531145 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501146 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1147 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041148
1149 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071150 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041151 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531152 content::Source<DownloadManager>(this),
1153 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041154 }
1155}
[email protected]da4a5582011-10-17 19:08:061156
[email protected]fc03de22011-12-06 23:28:121157void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061158 delegate_->UpdateItemInPersistentStore(download);
1159 int num_unopened = 0;
1160 for (DownloadMap::iterator it = history_downloads_.begin();
1161 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501162 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061163 ++num_unopened;
1164 }
1165 download_stats::RecordOpensOutstanding(num_unopened);
1166}
[email protected]5656f8a2011-11-17 16:12:581167
1168void DownloadManagerImpl::SetFileManager(DownloadFileManager* file_manager) {
1169 file_manager_ = file_manager;
1170}