blob: 918f4473d315735ffec997d059c71e21ccbbb075 [file] [log] [blame]
[email protected]0afff032012-01-06 20:55:001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]5656f8a2011-11-17 16:12:585#include "content/browser/download/download_manager_impl.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]e7557f172011-08-19 23:42:017#include <iterator>
8
[email protected]eda58402011-09-21 19:32:029#include "base/bind.h"
[email protected]2041cf342010-02-19 03:15:5910#include "base/callback.h"
[email protected]c6944272012-01-06 22:12:2811#include "base/debug/alias.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/file_util.h"
[email protected]503d03872011-05-06 08:36:2613#include "base/i18n/case_conversion.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/logging.h"
[email protected]7286e3fc2011-07-19 22:13:2415#include "base/stl_util.h"
[email protected]eda58402011-09-21 19:32:0216#include "base/stringprintf.h"
17#include "base/synchronization/lock.h"
18#include "base/sys_string_conversions.h"
[email protected]d2a8fb72010-01-21 05:31:4219#include "build/build_config.h"
[email protected]71bf3f5e2011-08-15 21:05:2220#include "content/browser/download/download_create_info.h"
21#include "content/browser/download/download_file_manager.h"
[email protected]c09a8fd2011-11-21 19:54:5022#include "content/browser/download/download_item_impl.h"
[email protected]bb1a4212011-08-22 22:38:2523#include "content/browser/download/download_persistent_store_info.h"
[email protected]da4a5582011-10-17 19:08:0624#include "content/browser/download/download_stats.h"
[email protected]be76b7e2011-10-13 12:57:5725#include "content/browser/download/interrupt_reasons.h"
[email protected]7324d1d2011-03-01 05:02:1626#include "content/browser/renderer_host/render_view_host.h"
27#include "content/browser/renderer_host/resource_dispatcher_host.h"
28#include "content/browser/tab_contents/tab_contents.h"
[email protected]ccb797302011-12-15 16:55:1129#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4930#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4431#include "content/public/browser/content_browser_client.h"
[email protected]1bd0ef12011-10-20 05:24:1732#include "content/public/browser/download_manager_delegate.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]a896ce32012-01-09 22:04:0739// TODO(benjhayden): Change this to DCHECK when we have more debugging
40// information from the next dev cycle, before the next stable/beta branch is
41// cut, in order to prevent unnecessary crashes on those channels. If we still
42// don't have root cause before the dev cycle after the next stable/beta
43// releases, uncomment it out to re-enable debugging checks. Whenever this macro
44// is toggled, the corresponding macro in download_database.cc should also
45// be toggled. When 96627 is fixed, this macro and all its usages can be
46// deleted or permanently changed to DCHECK as appropriate.
47#define CHECK_96627 CHECK
48
[email protected]631bb742011-11-02 11:29:3949using content::BrowserThread;
[email protected]98e814062012-01-27 00:35:4250using content::DownloadId;
[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 {
[email protected]27678b2a2012-02-04 22:09:1458 URLParams(const GURL& url, const GURL& referrer, int64 post_id)
59 : url_(url), referrer_(referrer), post_id_(post_id) {}
[email protected]fabf36d22011-10-28 21:50:1760 GURL url_;
61 GURL referrer_;
[email protected]27678b2a2012-02-04 22:09:1462 int64 post_id_;
[email protected]fabf36d22011-10-28 21:50:1763};
64
65struct RenderParams {
66 RenderParams(int rpi, int rvi)
67 : render_process_id_(rpi), render_view_id_(rvi) {}
68 int render_process_id_;
69 int render_view_id_;
70};
71
72void BeginDownload(const URLParams& url_params,
[email protected]0d4e30c2012-01-28 00:47:5373 bool prefer_cache,
[email protected]fabf36d22011-10-28 21:50:1774 const DownloadSaveInfo& save_info,
75 ResourceDispatcherHost* resource_dispatcher_host,
76 const RenderParams& render_params,
[email protected]df02aca2012-02-09 21:03:2077 content::ResourceContext* context) {
[email protected]c1ba99842012-01-19 20:56:0578 scoped_ptr<net::URLRequest> request(
79 new net::URLRequest(url_params.url_, resource_dispatcher_host));
[email protected]fabf36d22011-10-28 21:50:1780 request->set_referrer(url_params.referrer_.spec());
[email protected]27678b2a2012-02-04 22:09:1481 if (url_params.post_id_ >= 0) {
82 // The POST in this case does not have an actual body, and only works
83 // when retrieving data from cache. This is done because we don't want
84 // to do a re-POST without user consent, and currently don't have a good
85 // plan on how to display the UI for that.
86 DCHECK(prefer_cache);
87 request->set_method("POST");
88 scoped_refptr<net::UploadData> upload_data = new net::UploadData();
89 upload_data->set_identifier(url_params.post_id_);
90 request->set_upload(upload_data);
91 }
[email protected]c79a0c02011-08-22 22:37:3792 resource_dispatcher_host->BeginDownload(
[email protected]0d4e30c2012-01-28 00:47:5393 request.Pass(), prefer_cache, save_info,
[email protected]8e3ae68c2011-09-16 22:15:4794 DownloadResourceHandler::OnStartedCallback(),
[email protected]fabf36d22011-10-28 21:50:1795 render_params.render_process_id_,
96 render_params.render_view_id_,
[email protected]df02aca2012-02-09 21:03:2097 context);
[email protected]a0ce3282011-08-19 20:49:5298}
99
[email protected]33d22102012-01-25 17:46:53100class MapValueIteratorAdapter {
101 public:
102 explicit MapValueIteratorAdapter(
103 base::hash_map<int64, DownloadItem*>::const_iterator iter)
104 : iter_(iter) {
105 }
106 ~MapValueIteratorAdapter() {}
107
108 DownloadItem* operator*() { return iter_->second; }
109
110 MapValueIteratorAdapter& operator++() {
111 ++iter_;
112 return *this;
113 }
114
115 bool operator!=(const MapValueIteratorAdapter& that) const {
116 return iter_ != that.iter_;
117 }
118
119 private:
120 base::hash_map<int64, DownloadItem*>::const_iterator iter_;
121 // Allow copy and assign.
122};
123
[email protected]a0ce3282011-08-19 20:49:52124} // namespace
125
[email protected]99907362012-01-11 05:41:40126namespace content {
127
128// static
129DownloadManager* DownloadManager::Create(
[email protected]ef17c9a2012-02-09 05:08:09130 content::DownloadManagerDelegate* delegate,
131 net::NetLog* net_log) {
132 return new DownloadManagerImpl(delegate, net_log);
[email protected]99907362012-01-11 05:41:40133}
134
135} // namespace content
136
[email protected]5656f8a2011-11-17 16:12:58137DownloadManagerImpl::DownloadManagerImpl(
[email protected]ef17c9a2012-02-09 05:08:09138 content::DownloadManagerDelegate* delegate,
139 net::NetLog* net_log)
[email protected]5656f8a2011-11-17 16:12:58140 : shutdown_needed_(false),
141 browser_context_(NULL),
142 file_manager_(NULL),
[email protected]5656f8a2011-11-17 16:12:58143 delegate_(delegate),
[email protected]ef17c9a2012-02-09 05:08:09144 largest_db_handle_in_history_(DownloadItem::kUninitializedHandle),
145 net_log_(net_log) {
initial.commit09911bf2008-07-26 23:55:29146}
147
[email protected]5656f8a2011-11-17 16:12:58148DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13149 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29150}
151
[email protected]5656f8a2011-11-17 16:12:58152DownloadId DownloadManagerImpl::GetNextId() {
[email protected]98e814062012-01-27 00:35:42153 return delegate_->GetNextId();
[email protected]2909e342011-10-29 00:46:53154}
155
[email protected]fc03de22011-12-06 23:28:12156bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
157 return delegate_->ShouldOpenDownload(item);
158}
159
160bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
161 return delegate_->ShouldOpenFileBasedOnExtension(path);
162}
163
[email protected]5656f8a2011-11-17 16:12:58164void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50165 VLOG(20) << __FUNCTION__ << "()"
166 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13167 if (!shutdown_needed_)
168 return;
169 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29170
[email protected]75e51b52012-02-04 16:57:54171 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
[email protected]fb4f8d902011-09-16 06:07:08172 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13173
174 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18175 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17176 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
177 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13178 }
initial.commit09911bf2008-07-26 23:55:29179
[email protected]f04182f32010-12-10 19:12:07180 AssertContainersConsistent();
181
182 // Go through all downloads in downloads_. Dangerous ones we need to
183 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09184 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07185 DownloadItem* download = *it;
186
187 // Save iterator from potential erases in this set done by called code.
188 // Iterators after an erasure point are still valid for lists and
189 // associative containers such as sets.
190 it++;
191
[email protected]c09a8fd2011-11-21 19:54:50192 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29193 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07194 // The user hasn't accepted it, so we need to remove it
195 // from the disk. This may or may not result in it being
196 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12197 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07198 // removes and deletes it if it's known to the history service)
199 // so the only thing we know after calling this function is that
200 // the download was deleted if-and-only-if it was removed
201 // from all queues.
[email protected]303077002011-04-19 23:21:01202 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26203 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17204 download->Cancel(false);
205 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29206 }
207 }
208
[email protected]f04182f32010-12-10 19:12:07209 // At this point, all dangerous downloads have had their files removed
210 // and all in progress downloads have been cancelled. We can now delete
211 // anything left.
[email protected]9ccbb372008-10-10 18:50:32212
[email protected]5cd11b6e2011-06-10 20:30:59213 // Copy downloads_ to separate container so as not to set off checks
214 // in DownloadItem destruction.
215 DownloadSet downloads_to_delete;
216 downloads_to_delete.swap(downloads_);
217
initial.commit09911bf2008-07-26 23:55:29218 in_progress_.clear();
[email protected]70850c72011-01-11 17:31:27219 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59220 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59221 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29222
[email protected]41f558fb2012-01-09 22:59:58223 // We'll have nothing more to report to the observers after this point.
224 observers_.Clear();
225
[email protected]6d0146c2011-08-04 19:13:04226 DCHECK(save_page_downloads_.empty());
227
initial.commit09911bf2008-07-26 23:55:29228 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53229 delegate_->Shutdown();
initial.commit09911bf2008-07-26 23:55:29230}
231
[email protected]5656f8a2011-11-17 16:12:58232void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04233 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57234 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58235
[email protected]f04182f32010-12-10 19:12:07236 for (DownloadMap::iterator it = history_downloads_.begin();
237 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50238 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20239 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57240 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58241 }
[email protected]6aa4a1c02010-01-15 18:49:58242}
243
[email protected]5656f8a2011-11-17 16:12:58244void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04245 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57246 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34247
[email protected]f04182f32010-12-10 19:12:07248 for (DownloadMap::iterator it = history_downloads_.begin();
249 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50250 if (!it->second->IsTemporary() &&
251 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57252 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34253 }
[email protected]8ddbd66a2010-05-21 16:38:34254}
255
[email protected]5656f8a2011-11-17 16:12:58256void DownloadManagerImpl::SearchDownloads(const string16& query,
257 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26258 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42259
[email protected]f04182f32010-12-10 19:12:07260 for (DownloadMap::iterator it = history_downloads_.begin();
261 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42262 DownloadItem* download_item = it->second;
263
[email protected]c09a8fd2011-11-21 19:54:50264 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42265 continue;
266
267 // Display Incognito downloads only in Incognito window, and vice versa.
268 // The Incognito Downloads page will get the list of non-Incognito downloads
269 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50270 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42271 continue;
272
273 if (download_item->MatchesQuery(query_lower))
274 result->push_back(download_item);
275 }
[email protected]d3b12902010-08-16 23:39:42276}
277
initial.commit09911bf2008-07-26 23:55:29278// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58279bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03280 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29281 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
282 shutdown_needed_ = true;
283
[email protected]6d0c9fb2011-08-22 19:26:03284 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46285
[email protected]b39e7a88b2012-01-10 21:43:17286 // In test mode, there may be no ResourceDispatcherHost. In this case it's
287 // safe to avoid setting |file_manager_| because we only call a small set of
288 // functions, none of which need it.
[email protected]99907362012-01-11 05:41:40289 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get();
[email protected]b39e7a88b2012-01-10 21:43:17290 if (rdh) {
291 file_manager_ = rdh->download_file_manager();
292 DCHECK(file_manager_);
293 }
initial.commit09911bf2008-07-26 23:55:29294
initial.commit09911bf2008-07-26 23:55:29295 return true;
296}
297
[email protected]aa9881c2011-08-15 18:01:12298// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58299void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35301
[email protected]aa9881c2011-08-15 18:01:12302 if (delegate_->ShouldStartDownload(download_id))
303 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35304}
305
[email protected]5656f8a2011-11-17 16:12:58306void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
308 for (DownloadMap::iterator it = history_downloads_.begin();
309 it != history_downloads_.end(); ++it) {
310 CheckForFileRemoval(it->second);
311 }
312}
313
[email protected]5656f8a2011-11-17 16:12:58314void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
316 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50317 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48318 BrowserThread::PostTask(
319 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58320 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50321 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17322 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48323 }
324}
325
[email protected]5656f8a2011-11-17 16:12:58326void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48327 int64 db_handle, const FilePath& path) {
328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
329 if (!file_util::PathExists(path)) {
330 BrowserThread::PostTask(
331 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58332 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
333 this,
334 db_handle));
[email protected]9fc114672011-06-15 08:17:48335 }
336}
337
[email protected]5656f8a2011-11-17 16:12:58338void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
340 DownloadMap::iterator it = history_downloads_.find(db_handle);
341 if (it != history_downloads_.end()) {
342 DownloadItem* download_item = it->second;
343 download_item->OnDownloadedFileRemoved();
344 }
345}
346
[email protected]443853c62011-12-22 19:22:41347void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29349
[email protected]4cd82f72011-05-23 19:15:01350 DownloadItem* download = GetActiveDownloadItem(download_id);
351 if (!download)
352 return;
353
354 VLOG(20) << __FUNCTION__ << "()"
355 << " download = " << download->DebugString(true);
356
[email protected]c09a8fd2011-11-21 19:54:50357 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01358
[email protected]c09a8fd2011-11-21 19:54:50359 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29360 // We must ask the user for the place to put the download.
[email protected]a62d42902012-01-24 17:24:38361 WebContents* contents = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:26362
[email protected]4cd82f72011-05-23 19:15:01363 // |id_ptr| will be deleted in either FileSelected() or
[email protected]93af2272011-09-21 18:29:17364 // FileSelectionCancelled().
[email protected]4cd82f72011-05-23 19:15:01365 int32* id_ptr = new int32;
366 *id_ptr = download_id;
[email protected]795b76a2011-12-14 16:52:53367 FilePath target_path;
368 // If |download| is a potentially dangerous file, then |suggested_path|
369 // contains the intermediate name instead of the final download
370 // filename. The latter is GetTargetName().
[email protected]a62d42902012-01-24 17:24:38371 if (download->GetDangerType() !=
372 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
[email protected]795b76a2011-12-14 16:52:53373 target_path = suggested_path.DirName().Append(download->GetTargetName());
374 else
375 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26376
[email protected]795b76a2011-12-14 16:52:53377 delegate_->ChooseDownloadPath(contents, target_path,
378 reinterpret_cast<void*>(id_ptr));
[email protected]f5920322011-03-24 20:34:16379 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]75e51b52012-02-04 16:57:54380 SelectFileDialogDisplayed(this, download_id));
initial.commit09911bf2008-07-26 23:55:29381 } else {
382 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01383 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29384 }
385}
386
[email protected]37757c62011-12-20 20:07:12387content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58388 return browser_context_;
389}
390
391FilePath DownloadManagerImpl::LastDownloadPath() {
392 return last_download_path_;
393}
394
[email protected]ef17c9a2012-02-09 05:08:09395net::BoundNetLog DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41396 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
398
[email protected]ef17c9a2012-02-09 05:08:09399 net::BoundNetLog bound_net_log =
400 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]c09a8fd2011-11-21 19:54:50401 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29402 this, *info, new DownloadRequestHandle(request_handle),
[email protected]ef17c9a2012-02-09 05:08:09403 browser_context_->IsOffTheRecord(), bound_net_log);
[email protected]2909e342011-10-29 00:46:53404 int32 download_id = info->download_id.local();
[email protected]4cd82f72011-05-23 19:15:01405 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]d8472d92011-08-26 20:15:20406
[email protected]a896ce32012-01-09 22:04:07407 CHECK_96627(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29408 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01409 active_downloads_[download_id] = download;
[email protected]ef17c9a2012-02-09 05:08:09410
411 return bound_net_log;
[email protected]c2e76012010-12-23 21:10:29412}
413
[email protected]fc03de22011-12-06 23:28:12414DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
415 const FilePath& main_file_path,
416 const GURL& page_url,
417 bool is_otr,
418 DownloadItem::Observer* observer) {
[email protected]ef17c9a2012-02-09 05:08:09419 net::BoundNetLog bound_net_log =
420 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12421 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09422 this, main_file_path, page_url, is_otr, GetNextId(), bound_net_log);
[email protected]fc03de22011-12-06 23:28:12423
424 download->AddObserver(observer);
425
426 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
427 downloads_.insert(download);
428 save_page_downloads_[download->GetId()] = download;
429
430 // Will notify the observer in the callback.
431 delegate_->AddItemToPersistentStore(download);
432
433 return download;
434}
435
[email protected]795b76a2011-12-14 16:52:53436// For non-safe downloads with no prompting, |chosen_file| is the intermediate
437// path for saving the in-progress download. The final target filename for these
438// is |download->GetTargetName()|. For all other downloads (non-safe downloads
439// for which we have prompted for a save location, and all safe downloads),
440// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58441void DownloadManagerImpl::ContinueDownloadWithPath(
442 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01444 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39445
[email protected]c09a8fd2011-11-21 19:54:50446 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29447
[email protected]70850c72011-01-11 17:31:27448 // NOTE(ahendrickson) Eventually |active_downloads_| will replace
449 // |in_progress_|, but we don't want to change the semantics yet.
[email protected]4cd82f72011-05-23 19:15:01450 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]70850c72011-01-11 17:31:27451 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01452 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27453
[email protected]4cd82f72011-05-23 19:15:01454 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20455 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01456 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01457
458 VLOG(20) << __FUNCTION__ << "()"
459 << " download = " << download->DebugString(true);
460
461 in_progress_[download_id] = download;
initial.commit09911bf2008-07-26 23:55:29462
[email protected]adb2f3d12011-01-23 16:24:54463 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16464 FilePath download_path;
[email protected]385e93182012-01-30 17:11:03465 if (download->GetDangerType() !=
466 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
467 if (download->PromptUserForSaveLocation()) {
468 // When we prompt the user, we overwrite the FullPath with what the user
469 // wanted to use. Construct a file path using the previously determined
470 // intermediate filename and the new path.
471 // TODO(asanka): This can trample an in-progress download in the new
472 // target directory if it was using the same intermediate name.
473 FilePath file_name = download->GetSuggestedPath().BaseName();
474 download_path = download->GetFullPath().DirName().Append(file_name);
475 } else {
476 // The download's name is already set to an intermediate name, so no need
477 // to override.
478 download_path = download->GetFullPath();
479 }
480 } else {
481 // The download is a safe download. We need to rename it to its
482 // intermediate path. The final name after user confirmation will be set
483 // from DownloadItem::OnDownloadCompleting.
484 download_path = delegate_->GetIntermediatePath(download->GetFullPath());
485 }
[email protected]594cd7d2010-07-21 03:23:56486
[email protected]f5920322011-03-24 20:34:16487 BrowserThread::PostTask(
488 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17489 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12490 file_manager_, download->GetGlobalId(),
491 download_path));
[email protected]f5920322011-03-24 20:34:16492
493 download->Rename(download_path);
494
[email protected]2588ea9d2011-08-22 20:59:53495 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29496}
497
[email protected]443853c62011-12-22 19:22:41498void DownloadManagerImpl::UpdateDownload(int32 download_id,
499 int64 bytes_so_far,
500 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00501 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503 DownloadMap::iterator it = active_downloads_.find(download_id);
504 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29505 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26506 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41507 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]2588ea9d2011-08-22 20:59:53508 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27509 }
initial.commit09911bf2008-07-26 23:55:29510 }
511}
512
[email protected]5656f8a2011-11-17 16:12:58513void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
514 int64 size,
515 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50517 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
518 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32520
[email protected]c4f02c42011-01-24 21:55:06521 // If it's not in active_downloads_, that means it was cancelled; just
522 // ignore the notification.
523 if (active_downloads_.count(download_id) == 0)
524 return;
525
[email protected]adb2f3d12011-01-23 16:24:54526 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37527 download->OnAllDataSaved(size, hash);
[email protected]b09f1282011-09-14 00:37:45528
[email protected]fc03de22011-12-06 23:28:12529 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54530}
[email protected]9ccbb372008-10-10 18:50:32531
[email protected]fc03de22011-12-06 23:28:12532void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]a896ce32012-01-09 22:04:07533 // TODO(rdsmith): Change to DCHECK after http://crbug.com/96627 resolved.
[email protected]c09a8fd2011-11-21 19:54:50534 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]7d413112011-06-16 18:50:17535 CHECK(!ContainsKey(downloads_, download));
[email protected]c09a8fd2011-11-21 19:54:50536 CHECK(!ContainsKey(active_downloads_, download->GetId()));
537 CHECK(!ContainsKey(in_progress_, download->GetId()));
538 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17539 return;
540 }
541
542 // Should be in downloads_ if we're not REMOVING.
543 CHECK(ContainsKey(downloads_, download));
544
545 // Check history_downloads_ consistency.
[email protected]c09a8fd2011-11-21 19:54:50546 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
547 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17548 } else {
[email protected]fc03de22011-12-06 23:28:12549 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17550 it != history_downloads_.end(); ++it) {
[email protected]a896ce32012-01-09 22:04:07551 CHECK_96627(it->second != download);
[email protected]7d413112011-06-16 18:50:17552 }
553 }
554
[email protected]c09a8fd2011-11-21 19:54:50555 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34556 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50557 if (ContainsKey(active_downloads_, download->GetId())) {
558 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle)
559 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
560 if (DownloadItem::IN_PROGRESS != download->GetState())
561 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07562 }
[email protected]c09a8fd2011-11-21 19:54:50563 if (DownloadItem::IN_PROGRESS == download->GetState())
564 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59565}
566
[email protected]5656f8a2011-11-17 16:12:58567bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54568 // If we don't have all the data, the download is not ready for
569 // completion.
[email protected]c09a8fd2011-11-21 19:54:50570 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54571 return false;
[email protected]6a7fb042010-02-01 16:30:47572
[email protected]9d7ef802011-02-25 19:03:35573 // If the download is dangerous, but not yet validated, it's not ready for
574 // completion.
[email protected]c09a8fd2011-11-21 19:54:50575 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35576 return false;
577
[email protected]adb2f3d12011-01-23 16:24:54578 // If the download isn't active (e.g. has been cancelled) it's not
579 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50580 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54581 return false;
582
583 // If the download hasn't been inserted into the history system
584 // (which occurs strictly after file name determination, intermediate
585 // file rename, and UI display) then it's not ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50586 if (download->GetDbHandle() == DownloadItem::kUninitializedHandle)
[email protected]7054b592011-06-22 14:46:42587 return false;
588
589 return true;
[email protected]adb2f3d12011-01-23 16:24:54590}
591
[email protected]5656f8a2011-11-17 16:12:58592void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54593 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
594 VLOG(20) << __FUNCTION__ << "()" << " download = "
595 << download->DebugString(false);
596
597 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32598 return;
[email protected]9ccbb372008-10-10 18:50:32599
[email protected]adb2f3d12011-01-23 16:24:54600 // TODO(rdsmith): DCHECK that we only pass through this point
601 // once per download. The natural way to do this is by a state
602 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56603
[email protected]adb2f3d12011-01-23 16:24:54604 // Confirm we're in the proper set of states to be here;
[email protected]9d7ef802011-02-25 19:03:35605 // in in_progress_, have all data, have a history handle, (validated or safe).
[email protected]c09a8fd2011-11-21 19:54:50606 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
607 DCHECK_EQ(1u, in_progress_.count(download->GetId()));
608 DCHECK(download->AllDataSaved());
609 DCHECK(download->GetDbHandle() != DownloadItem::kUninitializedHandle);
610 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54611
[email protected]c2918652011-11-01 18:50:23612 // Give the delegate a chance to override.
613 if (!delegate_->ShouldCompleteDownload(download))
614 return;
615
[email protected]adb2f3d12011-01-23 16:24:54616 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
617 << download->DebugString(false);
618
619 // Remove the id from in_progress
[email protected]c09a8fd2011-11-21 19:54:50620 in_progress_.erase(download->GetId());
[email protected]adb2f3d12011-01-23 16:24:54621
[email protected]2588ea9d2011-08-22 20:59:53622 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54623
[email protected]f5920322011-03-24 20:34:16624 // Finish the download.
[email protected]48837962011-04-19 17:03:29625 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32626}
627
[email protected]fc03de22011-12-06 23:28:12628void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21630 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53631 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12632 active_downloads_.erase(download->GetId());
633 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27634}
635
[email protected]5656f8a2011-11-17 16:12:58636void DownloadManagerImpl::OnDownloadRenamedToFinalName(
637 int download_id,
638 const FilePath& full_path,
639 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50640 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16641 << " full_path = \"" << full_path.value() << "\""
642 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18643 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16644
[email protected]2e030682010-07-23 19:45:36645 DownloadItem* item = GetDownloadItem(download_id);
646 if (!item)
647 return;
[email protected]6cade212008-12-03 00:32:22648
[email protected]a62d42902012-01-24 17:24:38649 if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
[email protected]795b76a2011-12-14 16:52:53650 item->PromptUserForSaveLocation()) {
651 DCHECK_EQ(0, uniquifier)
652 << "We should not uniquify user supplied filenames or safe filenames "
653 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02654 }
655
[email protected]fabf36d22011-10-28 21:50:17656 BrowserThread::PostTask(
657 BrowserThread::FILE, FROM_HERE,
658 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50659 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32660
[email protected]f5920322011-03-24 20:34:16661 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50662 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32663
[email protected]f5920322011-03-24 20:34:16664 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53665 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29666}
667
[email protected]5656f8a2011-11-17 16:12:58668void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17669 DownloadItem* download = GetActiveDownload(download_id);
670 // A cancel at the right time could remove the download from the
671 // |active_downloads_| map before we get here.
672 if (!download)
673 return;
674
675 download->Cancel(true);
676}
677
[email protected]fc03de22011-12-06 23:28:12678void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20679 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20680
681 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50682 << " download = " << download->DebugString(true);
683
[email protected]93af2272011-09-21 18:29:17684 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21685 // This function is called from the DownloadItem, so DI state
686 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12687 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29688
[email protected]15d90ba2011-11-03 03:41:55689 if (file_manager_)
690 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29691}
692
[email protected]5656f8a2011-11-17 16:12:58693void DownloadManagerImpl::OnDownloadInterrupted(int32 download_id,
694 int64 size,
[email protected]0afff032012-01-06 20:55:00695 const std::string& hash_state,
[email protected]5656f8a2011-11-17 16:12:58696 InterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
698
699 DownloadItem* download = GetActiveDownload(download_id);
700 if (!download)
701 return;
702
[email protected]be76b7e2011-10-13 12:57:57703 VLOG(20) << __FUNCTION__ << "()"
704 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50705 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21706 << " size = " << size
707 << " download = " << download->DebugString(true);
708
[email protected]93af2272011-09-21 18:29:17709 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41710 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17711 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21712}
713
[email protected]5656f8a2011-11-17 16:12:58714DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26715 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
716 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26717 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21718 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26719
720 DownloadItem* download = it->second;
721
[email protected]47a881b2011-08-29 22:59:21722 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50723 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01724
[email protected]47a881b2011-08-29 22:59:21725 return download;
726}
[email protected]54610672011-07-18 18:24:43727
[email protected]5656f8a2011-11-17 16:12:58728void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17729 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
730 DCHECK(download);
731
732 // Clean up will happen when the history system create callback runs if we
733 // don't have a valid db_handle yet.
[email protected]c09a8fd2011-11-21 19:54:50734 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
735 in_progress_.erase(download->GetId());
736 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17737 delegate_->UpdateItemInPersistentStore(download);
738 }
739}
740
[email protected]fd3a82832012-01-19 20:35:12741bool DownloadManagerImpl::GenerateFileHash() {
742 return delegate_->GenerateFileHash();
743}
744
[email protected]5656f8a2011-11-17 16:12:58745content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
746 return delegate_;
747}
748
749void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17750 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35751 delegate_ = delegate;
752}
753
[email protected]5656f8a2011-11-17 16:12:58754int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04755 const DownloadVector& pending_deletes) {
756 if (pending_deletes.empty())
757 return 0;
758
759 // Delete from internal maps.
760 for (DownloadVector::const_iterator it = pending_deletes.begin();
761 it != pending_deletes.end();
762 ++it) {
763 DownloadItem* download = *it;
764 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50765 history_downloads_.erase(download->GetDbHandle());
766 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04767 downloads_.erase(download);
768 }
769
770 // Tell observers to refresh their views.
771 NotifyModelChanged();
772
773 // Delete the download items themselves.
774 const int num_deleted = static_cast<int>(pending_deletes.size());
775 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
776 return num_deleted;
777}
778
[email protected]fc03de22011-12-06 23:28:12779void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
780 if (history_downloads_.find(download->GetDbHandle()) ==
781 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17782 return;
783
784 // Make history update.
[email protected]93af2272011-09-21 18:29:17785 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29786
787 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04788 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07789 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29790}
791
[email protected]fd3a82832012-01-19 20:35:12792int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
793 base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53794 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29795
[email protected]a312a442010-12-15 23:40:33796 // All downloads visible to the user will be in the history,
797 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04798 DownloadVector pending_deletes;
799 for (DownloadMap::const_iterator it = history_downloads_.begin();
800 it != history_downloads_.end();
801 ++it) {
initial.commit09911bf2008-07-26 23:55:29802 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50803 if (download->GetStartTime() >= remove_begin &&
804 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04805 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12806 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28807 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29808 }
initial.commit09911bf2008-07-26 23:55:29809 }
[email protected]6d0146c2011-08-04 19:13:04810 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29811}
812
[email protected]fd3a82832012-01-19 20:35:12813int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59814 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29815}
816
[email protected]5656f8a2011-11-17 16:12:58817int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06818 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12819 // The null times make the date range unbounded.
820 return RemoveDownloadsBetween(base::Time(), base::Time());
821}
822
initial.commit09911bf2008-07-26 23:55:29823// Initiate a download of a specific URL. We send the request to the
824// ResourceDispatcherHost, and let it send us responses like a regular
825// download.
[email protected]0d4e30c2012-01-28 00:47:53826void DownloadManagerImpl::DownloadUrl(
827 const GURL& url,
828 const GURL& referrer,
829 const std::string& referrer_charset,
830 bool prefer_cache,
[email protected]27678b2a2012-02-04 22:09:14831 int64 post_id,
[email protected]0d4e30c2012-01-28 00:47:53832 const DownloadSaveInfo& save_info,
833 WebContents* web_contents) {
[email protected]c79a0c02011-08-22 22:37:37834 ResourceDispatcherHost* resource_dispatcher_host =
[email protected]99907362012-01-11 05:41:40835 ResourceDispatcherHost::Get();
[email protected]443853c62011-12-22 19:22:41836
[email protected]ed24fad2011-05-10 22:44:01837 // We send a pointer to content::ResourceContext, instead of the usual
838 // reference, so that a copy of the object isn't made.
[email protected]fabf36d22011-10-28 21:50:17839 // base::Bind can't handle 7 args, so we use URLParams and RenderParams.
840 BrowserThread::PostTask(
841 BrowserThread::IO, FROM_HERE,
[email protected]0d4e30c2012-01-28 00:47:53842 base::Bind(
843 &BeginDownload,
[email protected]27678b2a2012-02-04 22:09:14844 URLParams(url, referrer, post_id),
[email protected]0d4e30c2012-01-28 00:47:53845 prefer_cache,
846 save_info,
847 resource_dispatcher_host,
[email protected]fbc5e5f92012-01-02 06:08:32848 RenderParams(web_contents->GetRenderProcessHost()->GetID(),
849 web_contents->GetRenderViewHost()->routing_id()),
[email protected]df02aca2012-02-09 21:03:20850 web_contents->GetBrowserContext()->GetResourceContext()));
initial.commit09911bf2008-07-26 23:55:29851}
852
[email protected]5656f8a2011-11-17 16:12:58853void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29854 observers_.AddObserver(observer);
[email protected]75e51b52012-02-04 16:57:54855 observer->ModelChanged(this);
initial.commit09911bf2008-07-26 23:55:29856}
857
[email protected]5656f8a2011-11-17 16:12:58858void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29859 observers_.RemoveObserver(observer);
860}
861
[email protected]5656f8a2011-11-17 16:12:58862void DownloadManagerImpl::FileSelected(const FilePath& path, void* params) {
[email protected]4cd82f72011-05-23 19:15:01863 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
864
865 int32* id_ptr = reinterpret_cast<int32*>(params);
866 DCHECK(id_ptr != NULL);
867 int32 download_id = *id_ptr;
868 delete id_ptr;
869
870 DownloadItem* download = GetActiveDownloadItem(download_id);
871 if (!download)
872 return;
873 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
874 << " download = " << download->DebugString(true);
875
[email protected]c09a8fd2011-11-21 19:54:50876 if (download->PromptUserForSaveLocation())
[email protected]7ae7c2cb2009-01-06 23:31:41877 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35878
[email protected]4cd82f72011-05-23 19:15:01879 // Make sure the initial file name is set only once.
880 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29881}
882
[email protected]5656f8a2011-11-17 16:12:58883void DownloadManagerImpl::FileSelectionCanceled(void* params) {
initial.commit09911bf2008-07-26 23:55:29884 // The user didn't pick a place to save the file, so need to cancel the
885 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01886 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
887 int32* id_ptr = reinterpret_cast<int32*>(params);
888 DCHECK(id_ptr != NULL);
889 int32 download_id = *id_ptr;
890 delete id_ptr;
891
892 DownloadItem* download = GetActiveDownloadItem(download_id);
893 if (!download)
894 return;
895
896 VLOG(20) << __FUNCTION__ << "()"
897 << " download = " << download->DebugString(true);
898
[email protected]93af2272011-09-21 18:29:17899 // TODO(ahendrickson) -- This currently has no effect, as the download is
900 // not put on the active list until the file selection is complete. Need
901 // to put it on the active list earlier in the process.
902 RemoveFromActiveList(download);
903
904 download->OffThreadCancel(file_manager_);
[email protected]4cd82f72011-05-23 19:15:01905}
906
initial.commit09911bf2008-07-26 23:55:29907// Operations posted to us from the history service ----------------------------
908
909// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25910// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58911void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25912 std::vector<DownloadPersistentStoreInfo>* entries) {
[email protected]d8472d92011-08-26 20:15:20913 // TODO(rdsmith): Remove this and related logic when
[email protected]a896ce32012-01-09 22:04:07914 // http://crbug.com/96627 is fixed.
[email protected]d8472d92011-08-26 20:15:20915 largest_db_handle_in_history_ = 0;
916
initial.commit09911bf2008-07-26 23:55:29917 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]ef17c9a2012-02-09 05:08:09918 net::BoundNetLog bound_net_log =
919 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12920 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09921 this, GetNextId(), entries->at(i), bound_net_log);
[email protected]a896ce32012-01-09 22:04:07922 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]f04182f32010-12-10 19:12:07923 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50924 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50925 VLOG(20) << __FUNCTION__ << "()" << i << ">"
926 << " download = " << download->DebugString(true);
[email protected]d8472d92011-08-26 20:15:20927
[email protected]c09a8fd2011-11-21 19:54:50928 if (download->GetDbHandle() > largest_db_handle_in_history_)
929 largest_db_handle_in_history_ = download->GetDbHandle();
initial.commit09911bf2008-07-26 23:55:29930 }
[email protected]b0ab1d42010-02-24 19:29:28931 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48932 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29933}
934
[email protected]5656f8a2011-11-17 16:12:58935void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
936 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27937 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d2a8fb72010-01-21 05:31:42938
[email protected]a896ce32012-01-09 22:04:07939 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]1e9fe7ff2011-06-24 17:37:33940 // is fixed.
[email protected]2588ea9d2011-08-22 20:59:53941 CHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33942
[email protected]da4a5582011-10-17 19:08:06943 download_stats::RecordHistorySize(history_downloads_.size());
944
[email protected]c09a8fd2011-11-21 19:54:50945 DCHECK(download->GetDbHandle() == DownloadItem::kUninitializedHandle);
946 download->SetDbHandle(db_handle);
[email protected]5bcd73eb2011-03-23 21:14:02947
[email protected]a896ce32012-01-09 22:04:07948 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]d8472d92011-08-26 20:15:20949 // is fixed.
[email protected]a896ce32012-01-09 22:04:07950 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]c09a8fd2011-11-21 19:54:50951 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04952
953 // Show in the appropriate browser UI.
954 // This includes buttons to save or cancel, for a dangerous download.
955 ShowDownloadInBrowser(download);
956
957 // Inform interested objects about the new download.
958 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19959}
960
[email protected]2588ea9d2011-08-22 20:59:53961
[email protected]5656f8a2011-11-17 16:12:58962void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
963 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53964 if (save_page_downloads_.count(download_id)) {
965 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
966 } else if (active_downloads_.count(download_id)) {
967 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
968 }
969 // It's valid that we don't find a matching item, i.e. on shutdown.
970}
971
[email protected]f9a45b02011-06-30 23:49:19972// Once the new DownloadItem's creation info has been committed to the history
973// service, we associate the DownloadItem with the db handle, update our
974// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:58975void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
976 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:19977 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:45978 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:17979 if (!download)
[email protected]19420cc2011-07-18 17:43:45980 return;
[email protected]54610672011-07-18 18:24:43981
982 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
983 << " download_id = " << download_id
984 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:19985
[email protected]a896ce32012-01-09 22:04:07986 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:20987 int64 largest_handle = largest_db_handle_in_history_;
988 base::debug::Alias(&largest_handle);
[email protected]e5107ce2011-09-19 20:36:13989 int32 matching_item_download_id
990 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:50991 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:13992 base::debug::Alias(&matching_item_download_id);
993
[email protected]a896ce32012-01-09 22:04:07994 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:20995
[email protected]f9a45b02011-06-30 23:49:19996 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:29997
[email protected]93af2272011-09-21 18:29:17998 // If the download is still in progress, try to complete it.
999 //
1000 // Otherwise, download has been cancelled or interrupted before we've
1001 // received the DB handle. We post one final message to the history
1002 // service so that it can be properly in sync with the DownloadItem's
1003 // completion status, and also inform any observers so that they get
1004 // more than just the start notification.
1005 if (download->IsInProgress()) {
1006 MaybeCompleteDownload(download);
1007 } else {
[email protected]a896ce32012-01-09 22:04:071008 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]93af2272011-09-21 18:29:171009 // is fixed.
1010 CHECK(download->IsCancelled())
1011 << " download = " << download->DebugString(true);
1012 in_progress_.erase(download_id);
1013 active_downloads_.erase(download_id);
1014 delegate_->UpdateItemInPersistentStore(download);
1015 download->UpdateObservers();
1016 }
initial.commit09911bf2008-07-26 23:55:291017}
1018
[email protected]5656f8a2011-11-17 16:12:581019void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]8ddbd66a2010-05-21 16:38:341020 // The 'contents' may no longer exist if the user closed the tab before we
[email protected]99cb7f82011-07-28 17:27:261021 // get this start completion event.
[email protected]a62d42902012-01-24 17:24:381022 WebContents* content = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:261023
1024 // If the contents no longer exists, we ask the embedder to suggest another
1025 // tab.
[email protected]da1a27b2011-07-29 23:16:331026 if (!content)
[email protected]ef9572e2012-01-04 22:14:121027 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:531028
[email protected]0bfbf882011-12-22 18:19:271029 if (content && content->GetDelegate())
1030 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531031}
1032
[email protected]5656f8a2011-11-17 16:12:581033int DownloadManagerImpl::InProgressCount() const {
1034 return static_cast<int>(in_progress_.size());
1035}
1036
[email protected]6cade212008-12-03 00:32:221037// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581038void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411039 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381040}
[email protected]b0ab1d42010-02-24 19:29:281041
[email protected]5656f8a2011-11-17 16:12:581042void DownloadManagerImpl::NotifyModelChanged() {
[email protected]75e51b52012-02-04 16:57:541043 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged(this));
[email protected]b0ab1d42010-02-24 19:29:281044}
1045
[email protected]5656f8a2011-11-17 16:12:581046DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011047 // The |history_downloads_| map is indexed by the download's db_handle,
1048 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071049 for (DownloadMap::iterator it = history_downloads_.begin();
1050 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361051 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501052 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361053 return item;
1054 }
1055 return NULL;
1056}
1057
[email protected]5656f8a2011-11-17 16:12:581058DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361059 if (ContainsKey(active_downloads_, download_id))
1060 return active_downloads_[download_id];
1061 return NULL;
[email protected]4cd82f72011-05-23 19:15:011062}
1063
[email protected]57fd1252010-12-23 17:24:091064// Confirm that everything in all maps is also in |downloads_|, and that
1065// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581066void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071067#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091068 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041069 const DownloadMap* input_maps[] = {&active_downloads_,
1070 &history_downloads_,
1071 &save_page_downloads_};
1072 DownloadSet active_set, history_set, save_page_set;
1073 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1074 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091075 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1076 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041077 it != input_maps[i]->end(); ++it) {
1078 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071079 }
1080 }
[email protected]57fd1252010-12-23 17:24:091081
1082 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091083 DownloadSet downloads_union;
1084 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1085 DownloadSet remainder;
1086 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1087 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1088 downloads_.begin(), downloads_.end(),
1089 insert_it);
1090 DCHECK(remainder.empty());
1091 std::insert_iterator<DownloadSet>
1092 insert_union(downloads_union, downloads_union.end());
1093 std::set_union(downloads_union.begin(), downloads_union.end(),
1094 all_sets[i]->begin(), all_sets[i]->end(),
1095 insert_union);
1096 }
1097
1098 // Is everything in downloads_ present in one of the other sets?
1099 DownloadSet remainder;
1100 std::insert_iterator<DownloadSet>
1101 insert_remainder(remainder, remainder.begin());
1102 std::set_difference(downloads_.begin(), downloads_.end(),
1103 downloads_union.begin(), downloads_union.end(),
1104 insert_remainder);
1105 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071106#endif
1107}
1108
[email protected]6d0146c2011-08-04 19:13:041109// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531110// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041111// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531112// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1113// that the history event is update regardless of the order in which these two
1114// events complete.
[email protected]6d0146c2011-08-04 19:13:041115// If something removes the download item from the download manager (Remove,
1116// Shutdown) the result will be that the SavePage system will not be able to
1117// properly update the download item (which no longer exists) or the download
1118// history, but the action will complete properly anyway. This may lead to the
1119// history entry being wrong on a reload of chrome (specifically in the case of
1120// Initiation -> History Callback -> Removal -> Completion), but there's no way
1121// to solve that without canceling on Remove (which would then update the DB).
1122
[email protected]5656f8a2011-11-17 16:12:581123void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1124 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1126
1127 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1128 // This can happen if the download manager is shutting down and all maps
1129 // have been cleared.
1130 if (it == save_page_downloads_.end())
1131 return;
1132
1133 DownloadItem* download = it->second;
1134 if (!download) {
1135 NOTREACHED();
1136 return;
1137 }
1138
[email protected]a896ce32012-01-09 22:04:071139 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201140 int64 largest_handle = largest_db_handle_in_history_;
1141 base::debug::Alias(&largest_handle);
[email protected]a896ce32012-01-09 22:04:071142 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201143
[email protected]6d0146c2011-08-04 19:13:041144 AddDownloadItemToHistory(download, db_handle);
1145
1146 // Finalize this download if it finished before the history callback.
1147 if (!download->IsInProgress())
1148 SavePageDownloadFinished(download);
1149}
1150
[email protected]5656f8a2011-11-17 16:12:581151void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]c09a8fd2011-11-21 19:54:501152 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
[email protected]2588ea9d2011-08-22 20:59:531153 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501154 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1155 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041156
1157 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071158 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041159 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531160 content::Source<DownloadManager>(this),
1161 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041162 }
1163}
[email protected]da4a5582011-10-17 19:08:061164
[email protected]fc03de22011-12-06 23:28:121165void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061166 delegate_->UpdateItemInPersistentStore(download);
1167 int num_unopened = 0;
1168 for (DownloadMap::iterator it = history_downloads_.begin();
1169 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501170 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061171 ++num_unopened;
1172 }
1173 download_stats::RecordOpensOutstanding(num_unopened);
1174}
[email protected]5656f8a2011-11-17 16:12:581175
1176void DownloadManagerImpl::SetFileManager(DownloadFileManager* file_manager) {
1177 file_manager_ = file_manager;
1178}