blob: 4587e45eea7dcfc6208b2434b757617f0df9f49b [file] [log] [blame]
[email protected]bc34bd352012-01-04 21:08:211// 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"
initial.commit09911bf2008-07-26 23:55:2911#include "base/file_util.h"
[email protected]503d03872011-05-06 08:36:2612#include "base/i18n/case_conversion.h"
initial.commit09911bf2008-07-26 23:55:2913#include "base/logging.h"
[email protected]7286e3fc2011-07-19 22:13:2414#include "base/stl_util.h"
[email protected]eda58402011-09-21 19:32:0215#include "base/stringprintf.h"
16#include "base/synchronization/lock.h"
17#include "base/sys_string_conversions.h"
[email protected]d2a8fb72010-01-21 05:31:4218#include "build/build_config.h"
[email protected]71bf3f5e2011-08-15 21:05:2219#include "content/browser/download/download_create_info.h"
20#include "content/browser/download/download_file_manager.h"
[email protected]2909e342011-10-29 00:46:5321#include "content/browser/download/download_id_factory.h"
[email protected]c09a8fd2011-11-21 19:54:5022#include "content/browser/download/download_item_impl.h"
[email protected]bb1a4212011-08-22 22:38:2523#include "content/browser/download/download_persistent_store_info.h"
[email protected]da4a5582011-10-17 19:08:0624#include "content/browser/download/download_stats.h"
[email protected]71bf3f5e2011-08-15 21:05:2225#include "content/browser/download/download_status_updater.h"
[email protected]be76b7e2011-10-13 12:57:5726#include "content/browser/download/interrupt_reasons.h"
[email protected]7324d1d2011-03-01 05:02:1627#include "content/browser/renderer_host/render_view_host.h"
28#include "content/browser/renderer_host/resource_dispatcher_host.h"
29#include "content/browser/tab_contents/tab_contents.h"
[email protected]ccb797302011-12-15 16:55:1130#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4931#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4432#include "content/public/browser/content_browser_client.h"
[email protected]1bd0ef12011-10-20 05:24:1733#include "content/public/browser/download_manager_delegate.h"
[email protected]ad50def52011-10-19 23:17:0734#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1635#include "content/public/browser/notification_types.h"
[email protected]f3b1a082011-11-18 00:34:3036#include "content/public/browser/render_process_host.h"
[email protected]0bfbf882011-12-22 18:19:2737#include "content/public/browser/web_contents_delegate.h"
initial.commit09911bf2008-07-26 23:55:2938
[email protected]631bb742011-11-02 11:29:3939using content::BrowserThread;
[email protected]e582fdd2011-12-20 16:48:1740using content::DownloadItem;
[email protected]2a6bc3e2011-12-28 23:51:3341using content::WebContents;
[email protected]631bb742011-11-02 11:29:3942
[email protected]a0ce3282011-08-19 20:49:5243namespace {
44
[email protected]fabf36d22011-10-28 21:50:1745// Param structs exist because base::Bind can only handle 6 args.
46struct URLParams {
47 URLParams(const GURL& url, const GURL& referrer)
48 : url_(url), referrer_(referrer) {}
49 GURL url_;
50 GURL referrer_;
51};
52
53struct RenderParams {
54 RenderParams(int rpi, int rvi)
55 : render_process_id_(rpi), render_view_id_(rvi) {}
56 int render_process_id_;
57 int render_view_id_;
58};
59
60void BeginDownload(const URLParams& url_params,
61 const DownloadSaveInfo& save_info,
62 ResourceDispatcherHost* resource_dispatcher_host,
63 const RenderParams& render_params,
64 const content::ResourceContext* context) {
65 net::URLRequest* request = new net::URLRequest(url_params.url_,
66 resource_dispatcher_host);
67 request->set_referrer(url_params.referrer_.spec());
[email protected]c79a0c02011-08-22 22:37:3768 resource_dispatcher_host->BeginDownload(
[email protected]fabf36d22011-10-28 21:50:1769 request, save_info, true,
[email protected]8e3ae68c2011-09-16 22:15:4770 DownloadResourceHandler::OnStartedCallback(),
[email protected]fabf36d22011-10-28 21:50:1771 render_params.render_process_id_,
72 render_params.render_view_id_,
[email protected]c79a0c02011-08-22 22:37:3773 *context);
[email protected]a0ce3282011-08-19 20:49:5274}
75
76} // namespace
77
[email protected]5656f8a2011-11-17 16:12:5878DownloadManagerImpl::DownloadManagerImpl(
79 content::DownloadManagerDelegate* delegate,
80 DownloadIdFactory* id_factory,
81 DownloadStatusUpdater* status_updater)
82 : shutdown_needed_(false),
83 browser_context_(NULL),
84 file_manager_(NULL),
85 status_updater_((status_updater != NULL)
86 ? status_updater->AsWeakPtr()
87 : base::WeakPtr<DownloadStatusUpdater>()),
88 delegate_(delegate),
89 id_factory_(id_factory),
90 largest_db_handle_in_history_(DownloadItem::kUninitializedHandle) {
[email protected]eda58402011-09-21 19:32:0291 // NOTE(benjhayden): status_updater may be NULL when using
92 // TestingBrowserProcess.
93 if (status_updater_.get() != NULL)
[email protected]073ed7b2010-09-27 09:20:0294 status_updater_->AddDelegate(this);
initial.commit09911bf2008-07-26 23:55:2995}
96
[email protected]5656f8a2011-11-17 16:12:5897DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:1398 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:2999}
100
[email protected]5656f8a2011-11-17 16:12:58101DownloadId DownloadManagerImpl::GetNextId() {
[email protected]2909e342011-10-29 00:46:53102 return id_factory_->GetNextId();
103}
104
[email protected]fc03de22011-12-06 23:28:12105bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
106 return delegate_->ShouldOpenDownload(item);
107}
108
109bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
110 return delegate_->ShouldOpenFileBasedOnExtension(path);
111}
112
[email protected]5656f8a2011-11-17 16:12:58113void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50114 VLOG(20) << __FUNCTION__ << "()"
115 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13116 if (!shutdown_needed_)
117 return;
118 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29119
[email protected]326a6a92010-09-10 20:21:13120 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown());
[email protected]fb4f8d902011-09-16 06:07:08121 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13122
123 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18124 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17125 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
126 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13127 }
initial.commit09911bf2008-07-26 23:55:29128
[email protected]f04182f32010-12-10 19:12:07129 AssertContainersConsistent();
130
131 // Go through all downloads in downloads_. Dangerous ones we need to
132 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09133 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07134 DownloadItem* download = *it;
135
136 // Save iterator from potential erases in this set done by called code.
137 // Iterators after an erasure point are still valid for lists and
138 // associative containers such as sets.
139 it++;
140
[email protected]c09a8fd2011-11-21 19:54:50141 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29142 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07143 // The user hasn't accepted it, so we need to remove it
144 // from the disk. This may or may not result in it being
145 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12146 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07147 // removes and deletes it if it's known to the history service)
148 // so the only thing we know after calling this function is that
149 // the download was deleted if-and-only-if it was removed
150 // from all queues.
[email protected]303077002011-04-19 23:21:01151 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26152 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17153 download->Cancel(false);
154 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29155 }
156 }
157
[email protected]f04182f32010-12-10 19:12:07158 // At this point, all dangerous downloads have had their files removed
159 // and all in progress downloads have been cancelled. We can now delete
160 // anything left.
[email protected]9ccbb372008-10-10 18:50:32161
[email protected]5cd11b6e2011-06-10 20:30:59162 // Copy downloads_ to separate container so as not to set off checks
163 // in DownloadItem destruction.
164 DownloadSet downloads_to_delete;
165 downloads_to_delete.swap(downloads_);
166
initial.commit09911bf2008-07-26 23:55:29167 in_progress_.clear();
[email protected]70850c72011-01-11 17:31:27168 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59169 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59170 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29171
[email protected]bc34bd352012-01-04 21:08:21172 // We'll have nothing more to report to the observers after this point.
173 observers_.Clear();
174
[email protected]6d0146c2011-08-04 19:13:04175 DCHECK(save_page_downloads_.empty());
176
initial.commit09911bf2008-07-26 23:55:29177 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53178 delegate_->Shutdown();
[email protected]82f37b02010-07-29 22:04:57179
[email protected]bc34bd352012-01-04 21:08:21180 if (status_updater_)
181 status_updater_->RemoveDelegate(this);
182 status_updater_.reset();
initial.commit09911bf2008-07-26 23:55:29183}
184
[email protected]5656f8a2011-11-17 16:12:58185void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04186 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57187 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58188
[email protected]f04182f32010-12-10 19:12:07189 for (DownloadMap::iterator it = history_downloads_.begin();
190 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50191 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20192 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57193 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58194 }
[email protected]6aa4a1c02010-01-15 18:49:58195}
196
[email protected]5656f8a2011-11-17 16:12:58197void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04198 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57199 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34200
[email protected]f04182f32010-12-10 19:12:07201 for (DownloadMap::iterator it = history_downloads_.begin();
202 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50203 if (!it->second->IsTemporary() &&
204 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57205 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34206 }
[email protected]8ddbd66a2010-05-21 16:38:34207}
208
[email protected]5656f8a2011-11-17 16:12:58209void DownloadManagerImpl::SearchDownloads(const string16& query,
210 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26211 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42212
[email protected]f04182f32010-12-10 19:12:07213 for (DownloadMap::iterator it = history_downloads_.begin();
214 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42215 DownloadItem* download_item = it->second;
216
[email protected]c09a8fd2011-11-21 19:54:50217 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42218 continue;
219
220 // Display Incognito downloads only in Incognito window, and vice versa.
221 // The Incognito Downloads page will get the list of non-Incognito downloads
222 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50223 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42224 continue;
225
226 if (download_item->MatchesQuery(query_lower))
227 result->push_back(download_item);
228 }
[email protected]d3b12902010-08-16 23:39:42229}
230
initial.commit09911bf2008-07-26 23:55:29231// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58232bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03233 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29234 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
235 shutdown_needed_ = true;
236
[email protected]6d0c9fb2011-08-22 19:26:03237 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46238
[email protected]2941c2392010-07-15 22:54:30239 // In test mode, there may be no ResourceDispatcherHost. In this case it's
240 // safe to avoid setting |file_manager_| because we only call a small set of
241 // functions, none of which need it.
[email protected]a0ce3282011-08-19 20:49:52242 ResourceDispatcherHost* rdh =
243 content::GetContentClient()->browser()->GetResourceDispatcherHost();
[email protected]2941c2392010-07-15 22:54:30244 if (rdh) {
245 file_manager_ = rdh->download_file_manager();
246 DCHECK(file_manager_);
initial.commit09911bf2008-07-26 23:55:29247 }
248
initial.commit09911bf2008-07-26 23:55:29249 return true;
250}
251
[email protected]aa9881c2011-08-15 18:01:12252// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58253void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35255
[email protected]aa9881c2011-08-15 18:01:12256 if (delegate_->ShouldStartDownload(download_id))
257 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35258}
259
[email protected]5656f8a2011-11-17 16:12:58260void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
262 for (DownloadMap::iterator it = history_downloads_.begin();
263 it != history_downloads_.end(); ++it) {
264 CheckForFileRemoval(it->second);
265 }
266}
267
[email protected]5656f8a2011-11-17 16:12:58268void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
270 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50271 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48272 BrowserThread::PostTask(
273 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58274 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50275 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17276 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48277 }
278}
279
[email protected]5656f8a2011-11-17 16:12:58280void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48281 int64 db_handle, const FilePath& path) {
282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
283 if (!file_util::PathExists(path)) {
284 BrowserThread::PostTask(
285 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58286 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
287 this,
288 db_handle));
[email protected]9fc114672011-06-15 08:17:48289 }
290}
291
[email protected]5656f8a2011-11-17 16:12:58292void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
294 DownloadMap::iterator it = history_downloads_.find(db_handle);
295 if (it != history_downloads_.end()) {
296 DownloadItem* download_item = it->second;
297 download_item->OnDownloadedFileRemoved();
298 }
299}
300
[email protected]443853c62011-12-22 19:22:41301void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29303
[email protected]4cd82f72011-05-23 19:15:01304 DownloadItem* download = GetActiveDownloadItem(download_id);
305 if (!download)
306 return;
307
308 VLOG(20) << __FUNCTION__ << "()"
309 << " download = " << download->DebugString(true);
310
[email protected]c09a8fd2011-11-21 19:54:50311 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01312
[email protected]c09a8fd2011-11-21 19:54:50313 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29314 // We must ask the user for the place to put the download.
[email protected]ef9572e2012-01-04 22:14:12315 WebContents* contents = download->GetTabContents();
[email protected]99cb7f82011-07-28 17:27:26316
[email protected]4cd82f72011-05-23 19:15:01317 // |id_ptr| will be deleted in either FileSelected() or
[email protected]93af2272011-09-21 18:29:17318 // FileSelectionCancelled().
[email protected]4cd82f72011-05-23 19:15:01319 int32* id_ptr = new int32;
320 *id_ptr = download_id;
[email protected]795b76a2011-12-14 16:52:53321 FilePath target_path;
322 // If |download| is a potentially dangerous file, then |suggested_path|
323 // contains the intermediate name instead of the final download
324 // filename. The latter is GetTargetName().
325 if (download->GetDangerType() != DownloadStateInfo::NOT_DANGEROUS)
326 target_path = suggested_path.DirName().Append(download->GetTargetName());
327 else
328 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26329
[email protected]795b76a2011-12-14 16:52:53330 delegate_->ChooseDownloadPath(contents, target_path,
331 reinterpret_cast<void*>(id_ptr));
[email protected]f5920322011-03-24 20:34:16332 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]fed38252011-07-08 17:26:50333 SelectFileDialogDisplayed(download_id));
initial.commit09911bf2008-07-26 23:55:29334 } else {
335 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01336 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29337 }
338}
339
[email protected]37757c62011-12-20 20:07:12340content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58341 return browser_context_;
342}
343
344FilePath DownloadManagerImpl::LastDownloadPath() {
345 return last_download_path_;
346}
347
348void DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41349 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
351
[email protected]c09a8fd2011-11-21 19:54:50352 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29353 this, *info, new DownloadRequestHandle(request_handle),
354 browser_context_->IsOffTheRecord());
[email protected]2909e342011-10-29 00:46:53355 int32 download_id = info->download_id.local();
[email protected]4cd82f72011-05-23 19:15:01356 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]d8472d92011-08-26 20:15:20357
358 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved.
[email protected]821960a2011-08-23 20:40:03359 CHECK(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29360 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01361 active_downloads_[download_id] = download;
[email protected]c2e76012010-12-23 21:10:29362}
363
[email protected]fc03de22011-12-06 23:28:12364DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
365 const FilePath& main_file_path,
366 const GURL& page_url,
367 bool is_otr,
368 DownloadItem::Observer* observer) {
369 DownloadItem* download = new DownloadItemImpl(
370 this, main_file_path, page_url, is_otr, GetNextId());
371
372 download->AddObserver(observer);
373
374 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
375 downloads_.insert(download);
376 save_page_downloads_[download->GetId()] = download;
377
378 // Will notify the observer in the callback.
379 delegate_->AddItemToPersistentStore(download);
380
381 return download;
382}
383
[email protected]795b76a2011-12-14 16:52:53384// For non-safe downloads with no prompting, |chosen_file| is the intermediate
385// path for saving the in-progress download. The final target filename for these
386// is |download->GetTargetName()|. For all other downloads (non-safe downloads
387// for which we have prompted for a save location, and all safe downloads),
388// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58389void DownloadManagerImpl::ContinueDownloadWithPath(
390 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01392 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39393
[email protected]c09a8fd2011-11-21 19:54:50394 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29395
[email protected]70850c72011-01-11 17:31:27396 // NOTE(ahendrickson) Eventually |active_downloads_| will replace
397 // |in_progress_|, but we don't want to change the semantics yet.
[email protected]4cd82f72011-05-23 19:15:01398 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]70850c72011-01-11 17:31:27399 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01400 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27401
[email protected]4cd82f72011-05-23 19:15:01402 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20403 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01404 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01405
406 VLOG(20) << __FUNCTION__ << "()"
407 << " download = " << download->DebugString(true);
408
409 in_progress_[download_id] = download;
[email protected]5f8589fe2011-08-17 20:58:39410 UpdateDownloadProgress(); // Reflect entry into in_progress_.
initial.commit09911bf2008-07-26 23:55:29411
[email protected]adb2f3d12011-01-23 16:24:54412 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16413 FilePath download_path;
[email protected]ec865262011-08-23 20:01:48414 if (!delegate_->OverrideIntermediatePath(download, &download_path))
[email protected]c09a8fd2011-11-21 19:54:50415 download_path = download->GetFullPath();
[email protected]594cd7d2010-07-21 03:23:56416
[email protected]f5920322011-03-24 20:34:16417 BrowserThread::PostTask(
418 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17419 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12420 file_manager_, download->GetGlobalId(),
421 download_path));
[email protected]f5920322011-03-24 20:34:16422
423 download->Rename(download_path);
424
[email protected]2588ea9d2011-08-22 20:59:53425 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29426}
427
[email protected]443853c62011-12-22 19:22:41428void DownloadManagerImpl::UpdateDownload(int32 download_id,
429 int64 bytes_so_far,
430 int64 bytes_per_sec,
431 std::string hash_state) {
[email protected]70850c72011-01-11 17:31:27432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
433 DownloadMap::iterator it = active_downloads_.find(download_id);
434 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29435 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26436 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41437 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]5f8589fe2011-08-17 20:58:39438 UpdateDownloadProgress(); // Reflect size updates.
[email protected]2588ea9d2011-08-22 20:59:53439 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27440 }
initial.commit09911bf2008-07-26 23:55:29441 }
442}
443
[email protected]5656f8a2011-11-17 16:12:58444void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
445 int64 size,
446 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54447 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50448 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
449 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32451
[email protected]c4f02c42011-01-24 21:55:06452 // If it's not in active_downloads_, that means it was cancelled; just
453 // ignore the notification.
454 if (active_downloads_.count(download_id) == 0)
455 return;
456
[email protected]adb2f3d12011-01-23 16:24:54457 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37458 download->OnAllDataSaved(size, hash);
459 delegate_->OnResponseCompleted(download);
[email protected]b09f1282011-09-14 00:37:45460
[email protected]fc03de22011-12-06 23:28:12461 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54462}
[email protected]9ccbb372008-10-10 18:50:32463
[email protected]fc03de22011-12-06 23:28:12464void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]5cd11b6e2011-06-10 20:30:59465 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
[email protected]c09a8fd2011-11-21 19:54:50466 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]7d413112011-06-16 18:50:17467 CHECK(!ContainsKey(downloads_, download));
[email protected]c09a8fd2011-11-21 19:54:50468 CHECK(!ContainsKey(active_downloads_, download->GetId()));
469 CHECK(!ContainsKey(in_progress_, download->GetId()));
470 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17471 return;
472 }
473
474 // Should be in downloads_ if we're not REMOVING.
475 CHECK(ContainsKey(downloads_, download));
476
477 // Check history_downloads_ consistency.
[email protected]c09a8fd2011-11-21 19:54:50478 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
479 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17480 } else {
481 // TODO(rdsmith): Somewhat painful; make sure to disable in
482 // release builds after resolution of http://crbug.com/85408.
[email protected]fc03de22011-12-06 23:28:12483 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17484 it != history_downloads_.end(); ++it) {
485 CHECK(it->second != download);
486 }
487 }
488
[email protected]c09a8fd2011-11-21 19:54:50489 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34490 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50491 if (ContainsKey(active_downloads_, download->GetId())) {
492 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle)
493 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
494 if (DownloadItem::IN_PROGRESS != download->GetState())
495 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07496 }
[email protected]c09a8fd2011-11-21 19:54:50497 if (DownloadItem::IN_PROGRESS == download->GetState())
498 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59499}
500
[email protected]5656f8a2011-11-17 16:12:58501bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54502 // If we don't have all the data, the download is not ready for
503 // completion.
[email protected]c09a8fd2011-11-21 19:54:50504 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54505 return false;
[email protected]6a7fb042010-02-01 16:30:47506
[email protected]9d7ef802011-02-25 19:03:35507 // If the download is dangerous, but not yet validated, it's not ready for
508 // completion.
[email protected]c09a8fd2011-11-21 19:54:50509 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35510 return false;
511
[email protected]adb2f3d12011-01-23 16:24:54512 // If the download isn't active (e.g. has been cancelled) it's not
513 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50514 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54515 return false;
516
517 // If the download hasn't been inserted into the history system
518 // (which occurs strictly after file name determination, intermediate
519 // file rename, and UI display) then it's not ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50520 if (download->GetDbHandle() == DownloadItem::kUninitializedHandle)
[email protected]7054b592011-06-22 14:46:42521 return false;
522
523 return true;
[email protected]adb2f3d12011-01-23 16:24:54524}
525
[email protected]5656f8a2011-11-17 16:12:58526void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
528 VLOG(20) << __FUNCTION__ << "()" << " download = "
529 << download->DebugString(false);
530
531 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32532 return;
[email protected]9ccbb372008-10-10 18:50:32533
[email protected]adb2f3d12011-01-23 16:24:54534 // TODO(rdsmith): DCHECK that we only pass through this point
535 // once per download. The natural way to do this is by a state
536 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56537
[email protected]adb2f3d12011-01-23 16:24:54538 // Confirm we're in the proper set of states to be here;
[email protected]9d7ef802011-02-25 19:03:35539 // in in_progress_, have all data, have a history handle, (validated or safe).
[email protected]c09a8fd2011-11-21 19:54:50540 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
541 DCHECK_EQ(1u, in_progress_.count(download->GetId()));
542 DCHECK(download->AllDataSaved());
543 DCHECK(download->GetDbHandle() != DownloadItem::kUninitializedHandle);
544 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54545
[email protected]c2918652011-11-01 18:50:23546 // Give the delegate a chance to override.
547 if (!delegate_->ShouldCompleteDownload(download))
548 return;
549
[email protected]adb2f3d12011-01-23 16:24:54550 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
551 << download->DebugString(false);
552
553 // Remove the id from in_progress
[email protected]c09a8fd2011-11-21 19:54:50554 in_progress_.erase(download->GetId());
[email protected]5f8589fe2011-08-17 20:58:39555 UpdateDownloadProgress(); // Reflect removal from in_progress_.
[email protected]adb2f3d12011-01-23 16:24:54556
[email protected]2588ea9d2011-08-22 20:59:53557 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54558
[email protected]f5920322011-03-24 20:34:16559 // Finish the download.
[email protected]48837962011-04-19 17:03:29560 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32561}
562
[email protected]fc03de22011-12-06 23:28:12563void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21565 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53566 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12567 active_downloads_.erase(download->GetId());
568 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27569}
570
[email protected]5656f8a2011-11-17 16:12:58571void DownloadManagerImpl::OnDownloadRenamedToFinalName(
572 int download_id,
573 const FilePath& full_path,
574 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50575 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16576 << " full_path = \"" << full_path.value() << "\""
577 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16579
[email protected]2e030682010-07-23 19:45:36580 DownloadItem* item = GetDownloadItem(download_id);
581 if (!item)
582 return;
[email protected]6cade212008-12-03 00:32:22583
[email protected]795b76a2011-12-14 16:52:53584 if (item->GetDangerType() == DownloadStateInfo::NOT_DANGEROUS ||
585 item->PromptUserForSaveLocation()) {
586 DCHECK_EQ(0, uniquifier)
587 << "We should not uniquify user supplied filenames or safe filenames "
588 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02589 }
590
[email protected]fabf36d22011-10-28 21:50:17591 BrowserThread::PostTask(
592 BrowserThread::FILE, FROM_HERE,
593 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50594 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32595
[email protected]f5920322011-03-24 20:34:16596 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50597 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32598
[email protected]f5920322011-03-24 20:34:16599 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53600 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29601}
602
[email protected]5656f8a2011-11-17 16:12:58603void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17604 DownloadItem* download = GetActiveDownload(download_id);
605 // A cancel at the right time could remove the download from the
606 // |active_downloads_| map before we get here.
607 if (!download)
608 return;
609
610 download->Cancel(true);
611}
612
[email protected]fc03de22011-12-06 23:28:12613void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20614 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20615
616 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50617 << " download = " << download->DebugString(true);
618
[email protected]93af2272011-09-21 18:29:17619 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21620 // This function is called from the DownloadItem, so DI state
621 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12622 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29623
[email protected]15d90ba2011-11-03 03:41:55624 if (file_manager_)
625 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29626}
627
[email protected]5656f8a2011-11-17 16:12:58628void DownloadManagerImpl::OnDownloadInterrupted(int32 download_id,
629 int64 size,
[email protected]443853c62011-12-22 19:22:41630 std::string hash_state,
[email protected]5656f8a2011-11-17 16:12:58631 InterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21632 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
633
634 DownloadItem* download = GetActiveDownload(download_id);
635 if (!download)
636 return;
637
[email protected]be76b7e2011-10-13 12:57:57638 VLOG(20) << __FUNCTION__ << "()"
639 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50640 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21641 << " size = " << size
642 << " download = " << download->DebugString(true);
643
[email protected]93af2272011-09-21 18:29:17644 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41645 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17646 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21647}
648
[email protected]5656f8a2011-11-17 16:12:58649DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26650 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
651 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26652 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21653 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26654
655 DownloadItem* download = it->second;
656
[email protected]47a881b2011-08-29 22:59:21657 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50658 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01659
[email protected]47a881b2011-08-29 22:59:21660 return download;
661}
[email protected]54610672011-07-18 18:24:43662
[email protected]5656f8a2011-11-17 16:12:58663void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17664 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
665 DCHECK(download);
666
667 // Clean up will happen when the history system create callback runs if we
668 // don't have a valid db_handle yet.
[email protected]c09a8fd2011-11-21 19:54:50669 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
670 in_progress_.erase(download->GetId());
671 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17672 UpdateDownloadProgress(); // Reflect removal from in_progress_.
673 delegate_->UpdateItemInPersistentStore(download);
674 }
675}
676
[email protected]5656f8a2011-11-17 16:12:58677content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
678 return delegate_;
679}
680
681void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17682 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35683 delegate_ = delegate;
684}
685
[email protected]5656f8a2011-11-17 16:12:58686void DownloadManagerImpl::UpdateDownloadProgress() {
[email protected]5f8589fe2011-08-17 20:58:39687 delegate_->DownloadProgressUpdated();
[email protected]6a7fb042010-02-01 16:30:47688}
689
[email protected]5656f8a2011-11-17 16:12:58690int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04691 const DownloadVector& pending_deletes) {
692 if (pending_deletes.empty())
693 return 0;
694
695 // Delete from internal maps.
696 for (DownloadVector::const_iterator it = pending_deletes.begin();
697 it != pending_deletes.end();
698 ++it) {
699 DownloadItem* download = *it;
700 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50701 history_downloads_.erase(download->GetDbHandle());
702 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04703 downloads_.erase(download);
704 }
705
706 // Tell observers to refresh their views.
707 NotifyModelChanged();
708
709 // Delete the download items themselves.
710 const int num_deleted = static_cast<int>(pending_deletes.size());
711 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
712 return num_deleted;
713}
714
[email protected]fc03de22011-12-06 23:28:12715void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
716 if (history_downloads_.find(download->GetDbHandle()) ==
717 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17718 return;
719
720 // Make history update.
[email protected]93af2272011-09-21 18:29:17721 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29722
723 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04724 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07725 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29726}
727
[email protected]5656f8a2011-11-17 16:12:58728int DownloadManagerImpl::RemoveDownloadsBetween(const base::Time remove_begin,
729 const base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53730 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29731
[email protected]a312a442010-12-15 23:40:33732 // All downloads visible to the user will be in the history,
733 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04734 DownloadVector pending_deletes;
735 for (DownloadMap::const_iterator it = history_downloads_.begin();
736 it != history_downloads_.end();
737 ++it) {
initial.commit09911bf2008-07-26 23:55:29738 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50739 if (download->GetStartTime() >= remove_begin &&
740 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04741 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12742 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28743 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29744 }
initial.commit09911bf2008-07-26 23:55:29745 }
[email protected]6d0146c2011-08-04 19:13:04746 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29747}
748
[email protected]5656f8a2011-11-17 16:12:58749int DownloadManagerImpl::RemoveDownloads(const base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59750 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29751}
752
[email protected]5656f8a2011-11-17 16:12:58753int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06754 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12755 // The null times make the date range unbounded.
756 return RemoveDownloadsBetween(base::Time(), base::Time());
757}
758
initial.commit09911bf2008-07-26 23:55:29759// Initiate a download of a specific URL. We send the request to the
760// ResourceDispatcherHost, and let it send us responses like a regular
761// download.
[email protected]5656f8a2011-11-17 16:12:58762void DownloadManagerImpl::DownloadUrl(const GURL& url,
763 const GURL& referrer,
764 const std::string& referrer_charset,
[email protected]bb81f382012-01-03 22:45:44765 WebContents* web_contents) {
[email protected]ae8945192010-07-20 16:56:26766 DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(),
[email protected]bb81f382012-01-03 22:45:44767 web_contents);
[email protected]6aa4a1c02010-01-15 18:49:58768}
769
[email protected]5656f8a2011-11-17 16:12:58770void DownloadManagerImpl::DownloadUrlToFile(const GURL& url,
771 const GURL& referrer,
772 const std::string& referrer_charset,
773 const DownloadSaveInfo& save_info,
[email protected]fbc5e5f92012-01-02 06:08:32774 WebContents* web_contents) {
[email protected]c79a0c02011-08-22 22:37:37775 ResourceDispatcherHost* resource_dispatcher_host =
776 content::GetContentClient()->browser()->GetResourceDispatcherHost();
[email protected]443853c62011-12-22 19:22:41777
[email protected]ed24fad2011-05-10 22:44:01778 // We send a pointer to content::ResourceContext, instead of the usual
779 // reference, so that a copy of the object isn't made.
[email protected]fabf36d22011-10-28 21:50:17780 // base::Bind can't handle 7 args, so we use URLParams and RenderParams.
781 BrowserThread::PostTask(
782 BrowserThread::IO, FROM_HERE,
783 base::Bind(&BeginDownload,
784 URLParams(url, referrer), save_info, resource_dispatcher_host,
[email protected]fbc5e5f92012-01-02 06:08:32785 RenderParams(web_contents->GetRenderProcessHost()->GetID(),
786 web_contents->GetRenderViewHost()->routing_id()),
787 &web_contents->GetBrowserContext()->GetResourceContext()));
initial.commit09911bf2008-07-26 23:55:29788}
789
[email protected]5656f8a2011-11-17 16:12:58790void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29791 observers_.AddObserver(observer);
792 observer->ModelChanged();
793}
794
[email protected]5656f8a2011-11-17 16:12:58795void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29796 observers_.RemoveObserver(observer);
797}
798
[email protected]5656f8a2011-11-17 16:12:58799bool DownloadManagerImpl::IsDownloadProgressKnown() const {
[email protected]45f432e942011-10-25 18:17:22800 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02801 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50802 if (i->second->GetTotalBytes() <= 0)
[email protected]073ed7b2010-09-27 09:20:02803 return false;
804 }
805
806 return true;
807}
808
[email protected]5656f8a2011-11-17 16:12:58809int64 DownloadManagerImpl::GetInProgressDownloadCount() const {
[email protected]073ed7b2010-09-27 09:20:02810 return in_progress_.size();
811}
812
[email protected]5656f8a2011-11-17 16:12:58813int64 DownloadManagerImpl::GetReceivedDownloadBytes() const {
[email protected]073ed7b2010-09-27 09:20:02814 DCHECK(IsDownloadProgressKnown());
815 int64 received_bytes = 0;
[email protected]45f432e942011-10-25 18:17:22816 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02817 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50818 received_bytes += i->second->GetReceivedBytes();
[email protected]073ed7b2010-09-27 09:20:02819 }
820 return received_bytes;
821}
822
[email protected]5656f8a2011-11-17 16:12:58823int64 DownloadManagerImpl::GetTotalDownloadBytes() const {
[email protected]073ed7b2010-09-27 09:20:02824 DCHECK(IsDownloadProgressKnown());
825 int64 total_bytes = 0;
[email protected]45f432e942011-10-25 18:17:22826 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02827 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50828 total_bytes += i->second->GetTotalBytes();
[email protected]073ed7b2010-09-27 09:20:02829 }
830 return total_bytes;
831}
832
[email protected]5656f8a2011-11-17 16:12:58833void DownloadManagerImpl::FileSelected(const FilePath& path, void* params) {
[email protected]4cd82f72011-05-23 19:15:01834 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
835
836 int32* id_ptr = reinterpret_cast<int32*>(params);
837 DCHECK(id_ptr != NULL);
838 int32 download_id = *id_ptr;
839 delete id_ptr;
840
841 DownloadItem* download = GetActiveDownloadItem(download_id);
842 if (!download)
843 return;
844 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
845 << " download = " << download->DebugString(true);
846
[email protected]c09a8fd2011-11-21 19:54:50847 if (download->PromptUserForSaveLocation())
[email protected]7ae7c2cb2009-01-06 23:31:41848 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35849
[email protected]4cd82f72011-05-23 19:15:01850 // Make sure the initial file name is set only once.
851 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29852}
853
[email protected]5656f8a2011-11-17 16:12:58854void DownloadManagerImpl::FileSelectionCanceled(void* params) {
initial.commit09911bf2008-07-26 23:55:29855 // The user didn't pick a place to save the file, so need to cancel the
856 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01857 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
858 int32* id_ptr = reinterpret_cast<int32*>(params);
859 DCHECK(id_ptr != NULL);
860 int32 download_id = *id_ptr;
861 delete id_ptr;
862
863 DownloadItem* download = GetActiveDownloadItem(download_id);
864 if (!download)
865 return;
866
867 VLOG(20) << __FUNCTION__ << "()"
868 << " download = " << download->DebugString(true);
869
[email protected]93af2272011-09-21 18:29:17870 // TODO(ahendrickson) -- This currently has no effect, as the download is
871 // not put on the active list until the file selection is complete. Need
872 // to put it on the active list earlier in the process.
873 RemoveFromActiveList(download);
874
875 download->OffThreadCancel(file_manager_);
[email protected]4cd82f72011-05-23 19:15:01876}
877
initial.commit09911bf2008-07-26 23:55:29878// Operations posted to us from the history service ----------------------------
879
880// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25881// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58882void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25883 std::vector<DownloadPersistentStoreInfo>* entries) {
[email protected]d8472d92011-08-26 20:15:20884 // TODO(rdsmith): Remove this and related logic when
[email protected]639ddad2011-10-05 02:53:47885 // http://crbug.com/85408 is fixed.
[email protected]d8472d92011-08-26 20:15:20886 largest_db_handle_in_history_ = 0;
887
initial.commit09911bf2008-07-26 23:55:29888 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]fc03de22011-12-06 23:28:12889 DownloadItem* download = new DownloadItemImpl(
890 this, GetNextId(), entries->at(i));
[email protected]d8472d92011-08-26 20:15:20891 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved.
[email protected]c09a8fd2011-11-21 19:54:50892 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]f04182f32010-12-10 19:12:07893 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50894 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50895 VLOG(20) << __FUNCTION__ << "()" << i << ">"
896 << " download = " << download->DebugString(true);
[email protected]d8472d92011-08-26 20:15:20897
[email protected]c09a8fd2011-11-21 19:54:50898 if (download->GetDbHandle() > largest_db_handle_in_history_)
899 largest_db_handle_in_history_ = download->GetDbHandle();
initial.commit09911bf2008-07-26 23:55:29900 }
[email protected]b0ab1d42010-02-24 19:29:28901 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48902 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29903}
904
[email protected]5656f8a2011-11-17 16:12:58905void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
906 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27907 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d2a8fb72010-01-21 05:31:42908
[email protected]639ddad2011-10-05 02:53:47909 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/85408
[email protected]1e9fe7ff2011-06-24 17:37:33910 // is fixed.
[email protected]2588ea9d2011-08-22 20:59:53911 CHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33912
[email protected]da4a5582011-10-17 19:08:06913 download_stats::RecordHistorySize(history_downloads_.size());
914
[email protected]c09a8fd2011-11-21 19:54:50915 DCHECK(download->GetDbHandle() == DownloadItem::kUninitializedHandle);
916 download->SetDbHandle(db_handle);
[email protected]5bcd73eb2011-03-23 21:14:02917
[email protected]639ddad2011-10-05 02:53:47918 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/85408
[email protected]d8472d92011-08-26 20:15:20919 // is fixed.
[email protected]c09a8fd2011-11-21 19:54:50920 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
921 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04922
923 // Show in the appropriate browser UI.
924 // This includes buttons to save or cancel, for a dangerous download.
925 ShowDownloadInBrowser(download);
926
927 // Inform interested objects about the new download.
928 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19929}
930
[email protected]2588ea9d2011-08-22 20:59:53931
[email protected]5656f8a2011-11-17 16:12:58932void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
933 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53934 if (save_page_downloads_.count(download_id)) {
935 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
936 } else if (active_downloads_.count(download_id)) {
937 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
938 }
939 // It's valid that we don't find a matching item, i.e. on shutdown.
940}
941
[email protected]f9a45b02011-06-30 23:49:19942// Once the new DownloadItem's creation info has been committed to the history
943// service, we associate the DownloadItem with the db handle, update our
944// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:58945void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
946 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:19947 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:45948 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:17949 if (!download)
[email protected]19420cc2011-07-18 17:43:45950 return;
[email protected]54610672011-07-18 18:24:43951
952 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
953 << " download_id = " << download_id
954 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:19955
[email protected]d8472d92011-08-26 20:15:20956 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved.
[email protected]d8472d92011-08-26 20:15:20957 int64 largest_handle = largest_db_handle_in_history_;
958 base::debug::Alias(&largest_handle);
[email protected]e5107ce2011-09-19 20:36:13959 int32 matching_item_download_id
960 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:50961 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:13962 base::debug::Alias(&matching_item_download_id);
963
[email protected]61b75a52011-08-29 16:34:34964 CHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:20965
[email protected]f9a45b02011-06-30 23:49:19966 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:29967
[email protected]93af2272011-09-21 18:29:17968 // If the download is still in progress, try to complete it.
969 //
970 // Otherwise, download has been cancelled or interrupted before we've
971 // received the DB handle. We post one final message to the history
972 // service so that it can be properly in sync with the DownloadItem's
973 // completion status, and also inform any observers so that they get
974 // more than just the start notification.
975 if (download->IsInProgress()) {
976 MaybeCompleteDownload(download);
977 } else {
[email protected]639ddad2011-10-05 02:53:47978 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/85408
[email protected]93af2272011-09-21 18:29:17979 // is fixed.
980 CHECK(download->IsCancelled())
981 << " download = " << download->DebugString(true);
982 in_progress_.erase(download_id);
983 active_downloads_.erase(download_id);
984 delegate_->UpdateItemInPersistentStore(download);
985 download->UpdateObservers();
986 }
initial.commit09911bf2008-07-26 23:55:29987}
988
[email protected]5656f8a2011-11-17 16:12:58989void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]8ddbd66a2010-05-21 16:38:34990 // The 'contents' may no longer exist if the user closed the tab before we
[email protected]99cb7f82011-07-28 17:27:26991 // get this start completion event.
[email protected]2a6bc3e2011-12-28 23:51:33992 WebContents* content = download->GetTabContents();
[email protected]99cb7f82011-07-28 17:27:26993
994 // If the contents no longer exists, we ask the embedder to suggest another
995 // tab.
[email protected]da1a27b2011-07-29 23:16:33996 if (!content)
[email protected]ef9572e2012-01-04 22:14:12997 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:53998
[email protected]0bfbf882011-12-22 18:19:27999 if (content && content->GetDelegate())
1000 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531001}
1002
[email protected]5656f8a2011-11-17 16:12:581003int DownloadManagerImpl::InProgressCount() const {
1004 return static_cast<int>(in_progress_.size());
1005}
1006
[email protected]6cade212008-12-03 00:32:221007// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581008void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411009 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381010}
[email protected]b0ab1d42010-02-24 19:29:281011
[email protected]5656f8a2011-11-17 16:12:581012void DownloadManagerImpl::NotifyModelChanged() {
[email protected]b0ab1d42010-02-24 19:29:281013 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged());
1014}
1015
[email protected]5656f8a2011-11-17 16:12:581016DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011017 // The |history_downloads_| map is indexed by the download's db_handle,
1018 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071019 for (DownloadMap::iterator it = history_downloads_.begin();
1020 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361021 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501022 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361023 return item;
1024 }
1025 return NULL;
1026}
1027
[email protected]5656f8a2011-11-17 16:12:581028DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361029 if (ContainsKey(active_downloads_, download_id))
1030 return active_downloads_[download_id];
1031 return NULL;
[email protected]4cd82f72011-05-23 19:15:011032}
1033
[email protected]57fd1252010-12-23 17:24:091034// Confirm that everything in all maps is also in |downloads_|, and that
1035// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581036void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071037#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091038 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041039 const DownloadMap* input_maps[] = {&active_downloads_,
1040 &history_downloads_,
1041 &save_page_downloads_};
1042 DownloadSet active_set, history_set, save_page_set;
1043 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1044 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091045 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1046 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041047 it != input_maps[i]->end(); ++it) {
1048 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071049 }
1050 }
[email protected]57fd1252010-12-23 17:24:091051
1052 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091053 DownloadSet downloads_union;
1054 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1055 DownloadSet remainder;
1056 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1057 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1058 downloads_.begin(), downloads_.end(),
1059 insert_it);
1060 DCHECK(remainder.empty());
1061 std::insert_iterator<DownloadSet>
1062 insert_union(downloads_union, downloads_union.end());
1063 std::set_union(downloads_union.begin(), downloads_union.end(),
1064 all_sets[i]->begin(), all_sets[i]->end(),
1065 insert_union);
1066 }
1067
1068 // Is everything in downloads_ present in one of the other sets?
1069 DownloadSet remainder;
1070 std::insert_iterator<DownloadSet>
1071 insert_remainder(remainder, remainder.begin());
1072 std::set_difference(downloads_.begin(), downloads_.end(),
1073 downloads_union.begin(), downloads_union.end(),
1074 insert_remainder);
1075 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071076#endif
1077}
1078
[email protected]6d0146c2011-08-04 19:13:041079// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531080// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041081// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531082// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1083// that the history event is update regardless of the order in which these two
1084// events complete.
[email protected]6d0146c2011-08-04 19:13:041085// If something removes the download item from the download manager (Remove,
1086// Shutdown) the result will be that the SavePage system will not be able to
1087// properly update the download item (which no longer exists) or the download
1088// history, but the action will complete properly anyway. This may lead to the
1089// history entry being wrong on a reload of chrome (specifically in the case of
1090// Initiation -> History Callback -> Removal -> Completion), but there's no way
1091// to solve that without canceling on Remove (which would then update the DB).
1092
[email protected]5656f8a2011-11-17 16:12:581093void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1094 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041095 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1096
1097 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1098 // This can happen if the download manager is shutting down and all maps
1099 // have been cleared.
1100 if (it == save_page_downloads_.end())
1101 return;
1102
1103 DownloadItem* download = it->second;
1104 if (!download) {
1105 NOTREACHED();
1106 return;
1107 }
1108
[email protected]d8472d92011-08-26 20:15:201109 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved.
[email protected]d8472d92011-08-26 20:15:201110 int64 largest_handle = largest_db_handle_in_history_;
1111 base::debug::Alias(&largest_handle);
[email protected]61b75a52011-08-29 16:34:341112 CHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201113
[email protected]6d0146c2011-08-04 19:13:041114 AddDownloadItemToHistory(download, db_handle);
1115
1116 // Finalize this download if it finished before the history callback.
1117 if (!download->IsInProgress())
1118 SavePageDownloadFinished(download);
1119}
1120
[email protected]5656f8a2011-11-17 16:12:581121void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]c09a8fd2011-11-21 19:54:501122 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
[email protected]2588ea9d2011-08-22 20:59:531123 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501124 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1125 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041126
1127 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071128 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041129 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531130 content::Source<DownloadManager>(this),
1131 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041132 }
1133}
[email protected]da4a5582011-10-17 19:08:061134
[email protected]fc03de22011-12-06 23:28:121135void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061136 delegate_->UpdateItemInPersistentStore(download);
1137 int num_unopened = 0;
1138 for (DownloadMap::iterator it = history_downloads_.begin();
1139 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501140 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061141 ++num_unopened;
1142 }
1143 download_stats::RecordOpensOutstanding(num_unopened);
1144}
[email protected]5656f8a2011-11-17 16:12:581145
1146void DownloadManagerImpl::SetFileManager(DownloadFileManager* file_manager) {
1147 file_manager_ = file_manager;
1148}