blob: f3bb3b025fc2f9abf1bcad61be718c8de72d6602 [file] [log] [blame]
[email protected]0afff032012-01-06 20:55:001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]5656f8a2011-11-17 16:12:585#include "content/browser/download/download_manager_impl.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]e7557f172011-08-19 23:42:017#include <iterator>
8
[email protected]eda58402011-09-21 19:32:029#include "base/bind.h"
[email protected]2041cf342010-02-19 03:15:5910#include "base/callback.h"
[email protected]c6944272012-01-06 22:12:2811#include "base/debug/alias.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/file_util.h"
[email protected]503d03872011-05-06 08:36:2613#include "base/i18n/case_conversion.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/logging.h"
[email protected]7286e3fc2011-07-19 22:13:2415#include "base/stl_util.h"
[email protected]eda58402011-09-21 19:32:0216#include "base/stringprintf.h"
17#include "base/synchronization/lock.h"
18#include "base/sys_string_conversions.h"
[email protected]d2a8fb72010-01-21 05:31:4219#include "build/build_config.h"
[email protected]71bf3f5e2011-08-15 21:05:2220#include "content/browser/download/download_create_info.h"
21#include "content/browser/download/download_file_manager.h"
[email protected]2909e342011-10-29 00:46:5322#include "content/browser/download/download_id_factory.h"
[email protected]c09a8fd2011-11-21 19:54:5023#include "content/browser/download/download_item_impl.h"
[email protected]bb1a4212011-08-22 22:38:2524#include "content/browser/download/download_persistent_store_info.h"
[email protected]da4a5582011-10-17 19:08:0625#include "content/browser/download/download_stats.h"
[email protected]71bf3f5e2011-08-15 21:05:2226#include "content/browser/download/download_status_updater.h"
[email protected]be76b7e2011-10-13 12:57:5727#include "content/browser/download/interrupt_reasons.h"
[email protected]7324d1d2011-03-01 05:02:1628#include "content/browser/renderer_host/render_view_host.h"
29#include "content/browser/renderer_host/resource_dispatcher_host.h"
30#include "content/browser/tab_contents/tab_contents.h"
[email protected]ccb797302011-12-15 16:55:1131#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4932#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4433#include "content/public/browser/content_browser_client.h"
[email protected]1bd0ef12011-10-20 05:24:1734#include "content/public/browser/download_manager_delegate.h"
[email protected]ad50def52011-10-19 23:17:0735#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1636#include "content/public/browser/notification_types.h"
[email protected]f3b1a082011-11-18 00:34:3037#include "content/public/browser/render_process_host.h"
[email protected]0bfbf882011-12-22 18:19:2738#include "content/public/browser/web_contents_delegate.h"
initial.commit09911bf2008-07-26 23:55:2939
[email protected]a896ce32012-01-09 22:04:0740// TODO(benjhayden): Change this to DCHECK when we have more debugging
41// information from the next dev cycle, before the next stable/beta branch is
42// cut, in order to prevent unnecessary crashes on those channels. If we still
43// don't have root cause before the dev cycle after the next stable/beta
44// releases, uncomment it out to re-enable debugging checks. Whenever this macro
45// is toggled, the corresponding macro in download_database.cc should also
46// be toggled. When 96627 is fixed, this macro and all its usages can be
47// deleted or permanently changed to DCHECK as appropriate.
48#define CHECK_96627 CHECK
49
[email protected]631bb742011-11-02 11:29:3950using content::BrowserThread;
[email protected]e582fdd2011-12-20 16:48:1751using content::DownloadItem;
[email protected]2a6bc3e2011-12-28 23:51:3352using content::WebContents;
[email protected]631bb742011-11-02 11:29:3953
[email protected]a0ce3282011-08-19 20:49:5254namespace {
55
[email protected]fabf36d22011-10-28 21:50:1756// Param structs exist because base::Bind can only handle 6 args.
57struct URLParams {
58 URLParams(const GURL& url, const GURL& referrer)
59 : url_(url), referrer_(referrer) {}
60 GURL url_;
61 GURL referrer_;
62};
63
64struct RenderParams {
65 RenderParams(int rpi, int rvi)
66 : render_process_id_(rpi), render_view_id_(rvi) {}
67 int render_process_id_;
68 int render_view_id_;
69};
70
71void BeginDownload(const URLParams& url_params,
72 const DownloadSaveInfo& save_info,
73 ResourceDispatcherHost* resource_dispatcher_host,
74 const RenderParams& render_params,
75 const content::ResourceContext* context) {
76 net::URLRequest* request = new net::URLRequest(url_params.url_,
77 resource_dispatcher_host);
78 request->set_referrer(url_params.referrer_.spec());
[email protected]c79a0c02011-08-22 22:37:3779 resource_dispatcher_host->BeginDownload(
[email protected]fabf36d22011-10-28 21:50:1780 request, save_info, true,
[email protected]8e3ae68c2011-09-16 22:15:4781 DownloadResourceHandler::OnStartedCallback(),
[email protected]fabf36d22011-10-28 21:50:1782 render_params.render_process_id_,
83 render_params.render_view_id_,
[email protected]c79a0c02011-08-22 22:37:3784 *context);
[email protected]a0ce3282011-08-19 20:49:5285}
86
87} // namespace
88
[email protected]b4e74ee2012-01-10 19:31:5789namespace content {
90
91// static
92DownloadManager* DownloadManager::Create(
93 content::DownloadManagerDelegate* delegate,
94 DownloadIdFactory* id_factory,
95 DownloadStatusUpdater* status_updater) {
96 return new DownloadManagerImpl(delegate, id_factory, status_updater);
97}
98
99} // namespace content
100
[email protected]5656f8a2011-11-17 16:12:58101DownloadManagerImpl::DownloadManagerImpl(
102 content::DownloadManagerDelegate* delegate,
103 DownloadIdFactory* id_factory,
104 DownloadStatusUpdater* status_updater)
105 : shutdown_needed_(false),
106 browser_context_(NULL),
107 file_manager_(NULL),
108 status_updater_((status_updater != NULL)
109 ? status_updater->AsWeakPtr()
110 : base::WeakPtr<DownloadStatusUpdater>()),
111 delegate_(delegate),
112 id_factory_(id_factory),
113 largest_db_handle_in_history_(DownloadItem::kUninitializedHandle) {
[email protected]eda58402011-09-21 19:32:02114 // NOTE(benjhayden): status_updater may be NULL when using
115 // TestingBrowserProcess.
116 if (status_updater_.get() != NULL)
[email protected]073ed7b2010-09-27 09:20:02117 status_updater_->AddDelegate(this);
initial.commit09911bf2008-07-26 23:55:29118}
119
[email protected]5656f8a2011-11-17 16:12:58120DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13121 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29122}
123
[email protected]5656f8a2011-11-17 16:12:58124DownloadId DownloadManagerImpl::GetNextId() {
[email protected]2909e342011-10-29 00:46:53125 return id_factory_->GetNextId();
126}
127
[email protected]fc03de22011-12-06 23:28:12128bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
129 return delegate_->ShouldOpenDownload(item);
130}
131
132bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
133 return delegate_->ShouldOpenFileBasedOnExtension(path);
134}
135
[email protected]5656f8a2011-11-17 16:12:58136void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50137 VLOG(20) << __FUNCTION__ << "()"
138 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13139 if (!shutdown_needed_)
140 return;
141 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29142
[email protected]326a6a92010-09-10 20:21:13143 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown());
[email protected]fb4f8d902011-09-16 06:07:08144 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13145
146 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18147 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17148 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
149 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13150 }
initial.commit09911bf2008-07-26 23:55:29151
[email protected]f04182f32010-12-10 19:12:07152 AssertContainersConsistent();
153
154 // Go through all downloads in downloads_. Dangerous ones we need to
155 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09156 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07157 DownloadItem* download = *it;
158
159 // Save iterator from potential erases in this set done by called code.
160 // Iterators after an erasure point are still valid for lists and
161 // associative containers such as sets.
162 it++;
163
[email protected]c09a8fd2011-11-21 19:54:50164 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29165 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07166 // The user hasn't accepted it, so we need to remove it
167 // from the disk. This may or may not result in it being
168 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12169 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07170 // removes and deletes it if it's known to the history service)
171 // so the only thing we know after calling this function is that
172 // the download was deleted if-and-only-if it was removed
173 // from all queues.
[email protected]303077002011-04-19 23:21:01174 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26175 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17176 download->Cancel(false);
177 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29178 }
179 }
180
[email protected]f04182f32010-12-10 19:12:07181 // At this point, all dangerous downloads have had their files removed
182 // and all in progress downloads have been cancelled. We can now delete
183 // anything left.
[email protected]9ccbb372008-10-10 18:50:32184
[email protected]5cd11b6e2011-06-10 20:30:59185 // Copy downloads_ to separate container so as not to set off checks
186 // in DownloadItem destruction.
187 DownloadSet downloads_to_delete;
188 downloads_to_delete.swap(downloads_);
189
initial.commit09911bf2008-07-26 23:55:29190 in_progress_.clear();
[email protected]70850c72011-01-11 17:31:27191 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59192 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59193 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29194
[email protected]41f558fb2012-01-09 22:59:58195 // We'll have nothing more to report to the observers after this point.
196 observers_.Clear();
197
[email protected]6d0146c2011-08-04 19:13:04198 DCHECK(save_page_downloads_.empty());
199
initial.commit09911bf2008-07-26 23:55:29200 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53201 delegate_->Shutdown();
[email protected]82f37b02010-07-29 22:04:57202
[email protected]41f558fb2012-01-09 22:59:58203 if (status_updater_)
204 status_updater_->RemoveDelegate(this);
205 status_updater_.reset();
initial.commit09911bf2008-07-26 23:55:29206}
207
[email protected]5656f8a2011-11-17 16:12:58208void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04209 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57210 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58211
[email protected]f04182f32010-12-10 19:12:07212 for (DownloadMap::iterator it = history_downloads_.begin();
213 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50214 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20215 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57216 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58217 }
[email protected]6aa4a1c02010-01-15 18:49:58218}
219
[email protected]5656f8a2011-11-17 16:12:58220void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04221 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57222 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34223
[email protected]f04182f32010-12-10 19:12:07224 for (DownloadMap::iterator it = history_downloads_.begin();
225 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50226 if (!it->second->IsTemporary() &&
227 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57228 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34229 }
[email protected]8ddbd66a2010-05-21 16:38:34230}
231
[email protected]5656f8a2011-11-17 16:12:58232void DownloadManagerImpl::SearchDownloads(const string16& query,
233 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26234 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42235
[email protected]f04182f32010-12-10 19:12:07236 for (DownloadMap::iterator it = history_downloads_.begin();
237 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42238 DownloadItem* download_item = it->second;
239
[email protected]c09a8fd2011-11-21 19:54:50240 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42241 continue;
242
243 // Display Incognito downloads only in Incognito window, and vice versa.
244 // The Incognito Downloads page will get the list of non-Incognito downloads
245 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50246 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42247 continue;
248
249 if (download_item->MatchesQuery(query_lower))
250 result->push_back(download_item);
251 }
[email protected]d3b12902010-08-16 23:39:42252}
253
initial.commit09911bf2008-07-26 23:55:29254// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58255bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03256 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29257 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
258 shutdown_needed_ = true;
259
[email protected]6d0c9fb2011-08-22 19:26:03260 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46261
[email protected]b4e74ee2012-01-10 19:31:57262 file_manager_ = ResourceDispatcherHost::Get()->download_file_manager();
263 DCHECK(file_manager_);
initial.commit09911bf2008-07-26 23:55:29264
initial.commit09911bf2008-07-26 23:55:29265 return true;
266}
267
[email protected]aa9881c2011-08-15 18:01:12268// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58269void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35271
[email protected]aa9881c2011-08-15 18:01:12272 if (delegate_->ShouldStartDownload(download_id))
273 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35274}
275
[email protected]5656f8a2011-11-17 16:12:58276void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
278 for (DownloadMap::iterator it = history_downloads_.begin();
279 it != history_downloads_.end(); ++it) {
280 CheckForFileRemoval(it->second);
281 }
282}
283
[email protected]5656f8a2011-11-17 16:12:58284void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
286 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50287 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48288 BrowserThread::PostTask(
289 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58290 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50291 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17292 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48293 }
294}
295
[email protected]5656f8a2011-11-17 16:12:58296void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48297 int64 db_handle, const FilePath& path) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
299 if (!file_util::PathExists(path)) {
300 BrowserThread::PostTask(
301 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58302 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
303 this,
304 db_handle));
[email protected]9fc114672011-06-15 08:17:48305 }
306}
307
[email protected]5656f8a2011-11-17 16:12:58308void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
310 DownloadMap::iterator it = history_downloads_.find(db_handle);
311 if (it != history_downloads_.end()) {
312 DownloadItem* download_item = it->second;
313 download_item->OnDownloadedFileRemoved();
314 }
315}
316
[email protected]443853c62011-12-22 19:22:41317void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29319
[email protected]4cd82f72011-05-23 19:15:01320 DownloadItem* download = GetActiveDownloadItem(download_id);
321 if (!download)
322 return;
323
324 VLOG(20) << __FUNCTION__ << "()"
325 << " download = " << download->DebugString(true);
326
[email protected]c09a8fd2011-11-21 19:54:50327 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01328
[email protected]c09a8fd2011-11-21 19:54:50329 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29330 // We must ask the user for the place to put the download.
[email protected]ef9572e2012-01-04 22:14:12331 WebContents* contents = download->GetTabContents();
[email protected]99cb7f82011-07-28 17:27:26332
[email protected]4cd82f72011-05-23 19:15:01333 // |id_ptr| will be deleted in either FileSelected() or
[email protected]93af2272011-09-21 18:29:17334 // FileSelectionCancelled().
[email protected]4cd82f72011-05-23 19:15:01335 int32* id_ptr = new int32;
336 *id_ptr = download_id;
[email protected]795b76a2011-12-14 16:52:53337 FilePath target_path;
338 // If |download| is a potentially dangerous file, then |suggested_path|
339 // contains the intermediate name instead of the final download
340 // filename. The latter is GetTargetName().
341 if (download->GetDangerType() != DownloadStateInfo::NOT_DANGEROUS)
342 target_path = suggested_path.DirName().Append(download->GetTargetName());
343 else
344 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26345
[email protected]795b76a2011-12-14 16:52:53346 delegate_->ChooseDownloadPath(contents, target_path,
347 reinterpret_cast<void*>(id_ptr));
[email protected]f5920322011-03-24 20:34:16348 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]fed38252011-07-08 17:26:50349 SelectFileDialogDisplayed(download_id));
initial.commit09911bf2008-07-26 23:55:29350 } else {
351 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01352 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29353 }
354}
355
[email protected]37757c62011-12-20 20:07:12356content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58357 return browser_context_;
358}
359
360FilePath DownloadManagerImpl::LastDownloadPath() {
361 return last_download_path_;
362}
363
364void DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41365 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
367
[email protected]c09a8fd2011-11-21 19:54:50368 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29369 this, *info, new DownloadRequestHandle(request_handle),
370 browser_context_->IsOffTheRecord());
[email protected]2909e342011-10-29 00:46:53371 int32 download_id = info->download_id.local();
[email protected]4cd82f72011-05-23 19:15:01372 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]d8472d92011-08-26 20:15:20373
[email protected]a896ce32012-01-09 22:04:07374 CHECK_96627(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29375 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01376 active_downloads_[download_id] = download;
[email protected]c2e76012010-12-23 21:10:29377}
378
[email protected]fc03de22011-12-06 23:28:12379DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
380 const FilePath& main_file_path,
381 const GURL& page_url,
382 bool is_otr,
383 DownloadItem::Observer* observer) {
384 DownloadItem* download = new DownloadItemImpl(
385 this, main_file_path, page_url, is_otr, GetNextId());
386
387 download->AddObserver(observer);
388
389 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
390 downloads_.insert(download);
391 save_page_downloads_[download->GetId()] = download;
392
393 // Will notify the observer in the callback.
394 delegate_->AddItemToPersistentStore(download);
395
396 return download;
397}
398
[email protected]795b76a2011-12-14 16:52:53399// For non-safe downloads with no prompting, |chosen_file| is the intermediate
400// path for saving the in-progress download. The final target filename for these
401// is |download->GetTargetName()|. For all other downloads (non-safe downloads
402// for which we have prompted for a save location, and all safe downloads),
403// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58404void DownloadManagerImpl::ContinueDownloadWithPath(
405 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18406 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01407 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39408
[email protected]c09a8fd2011-11-21 19:54:50409 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29410
[email protected]70850c72011-01-11 17:31:27411 // NOTE(ahendrickson) Eventually |active_downloads_| will replace
412 // |in_progress_|, but we don't want to change the semantics yet.
[email protected]4cd82f72011-05-23 19:15:01413 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]70850c72011-01-11 17:31:27414 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01415 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27416
[email protected]4cd82f72011-05-23 19:15:01417 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20418 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01419 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01420
421 VLOG(20) << __FUNCTION__ << "()"
422 << " download = " << download->DebugString(true);
423
424 in_progress_[download_id] = download;
[email protected]5f8589fe2011-08-17 20:58:39425 UpdateDownloadProgress(); // Reflect entry into in_progress_.
initial.commit09911bf2008-07-26 23:55:29426
[email protected]adb2f3d12011-01-23 16:24:54427 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16428 FilePath download_path;
[email protected]ec865262011-08-23 20:01:48429 if (!delegate_->OverrideIntermediatePath(download, &download_path))
[email protected]c09a8fd2011-11-21 19:54:50430 download_path = download->GetFullPath();
[email protected]594cd7d2010-07-21 03:23:56431
[email protected]f5920322011-03-24 20:34:16432 BrowserThread::PostTask(
433 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17434 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12435 file_manager_, download->GetGlobalId(),
436 download_path));
[email protected]f5920322011-03-24 20:34:16437
438 download->Rename(download_path);
439
[email protected]2588ea9d2011-08-22 20:59:53440 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29441}
442
[email protected]443853c62011-12-22 19:22:41443void DownloadManagerImpl::UpdateDownload(int32 download_id,
444 int64 bytes_so_far,
445 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00446 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27447 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
448 DownloadMap::iterator it = active_downloads_.find(download_id);
449 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29450 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26451 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41452 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]5f8589fe2011-08-17 20:58:39453 UpdateDownloadProgress(); // Reflect size updates.
[email protected]2588ea9d2011-08-22 20:59:53454 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27455 }
initial.commit09911bf2008-07-26 23:55:29456 }
457}
458
[email protected]5656f8a2011-11-17 16:12:58459void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
460 int64 size,
461 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50463 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
464 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32466
[email protected]c4f02c42011-01-24 21:55:06467 // If it's not in active_downloads_, that means it was cancelled; just
468 // ignore the notification.
469 if (active_downloads_.count(download_id) == 0)
470 return;
471
[email protected]adb2f3d12011-01-23 16:24:54472 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37473 download->OnAllDataSaved(size, hash);
474 delegate_->OnResponseCompleted(download);
[email protected]b09f1282011-09-14 00:37:45475
[email protected]fc03de22011-12-06 23:28:12476 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54477}
[email protected]9ccbb372008-10-10 18:50:32478
[email protected]fc03de22011-12-06 23:28:12479void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]a896ce32012-01-09 22:04:07480 // TODO(rdsmith): Change to DCHECK after http://crbug.com/96627 resolved.
[email protected]c09a8fd2011-11-21 19:54:50481 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]7d413112011-06-16 18:50:17482 CHECK(!ContainsKey(downloads_, download));
[email protected]c09a8fd2011-11-21 19:54:50483 CHECK(!ContainsKey(active_downloads_, download->GetId()));
484 CHECK(!ContainsKey(in_progress_, download->GetId()));
485 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17486 return;
487 }
488
489 // Should be in downloads_ if we're not REMOVING.
490 CHECK(ContainsKey(downloads_, download));
491
492 // Check history_downloads_ consistency.
[email protected]c09a8fd2011-11-21 19:54:50493 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
494 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17495 } else {
[email protected]fc03de22011-12-06 23:28:12496 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17497 it != history_downloads_.end(); ++it) {
[email protected]a896ce32012-01-09 22:04:07498 CHECK_96627(it->second != download);
[email protected]7d413112011-06-16 18:50:17499 }
500 }
501
[email protected]c09a8fd2011-11-21 19:54:50502 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34503 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50504 if (ContainsKey(active_downloads_, download->GetId())) {
505 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle)
506 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
507 if (DownloadItem::IN_PROGRESS != download->GetState())
508 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07509 }
[email protected]c09a8fd2011-11-21 19:54:50510 if (DownloadItem::IN_PROGRESS == download->GetState())
511 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59512}
513
[email protected]5656f8a2011-11-17 16:12:58514bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54515 // If we don't have all the data, the download is not ready for
516 // completion.
[email protected]c09a8fd2011-11-21 19:54:50517 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54518 return false;
[email protected]6a7fb042010-02-01 16:30:47519
[email protected]9d7ef802011-02-25 19:03:35520 // If the download is dangerous, but not yet validated, it's not ready for
521 // completion.
[email protected]c09a8fd2011-11-21 19:54:50522 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35523 return false;
524
[email protected]adb2f3d12011-01-23 16:24:54525 // If the download isn't active (e.g. has been cancelled) it's not
526 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50527 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54528 return false;
529
530 // If the download hasn't been inserted into the history system
531 // (which occurs strictly after file name determination, intermediate
532 // file rename, and UI display) then it's not ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50533 if (download->GetDbHandle() == DownloadItem::kUninitializedHandle)
[email protected]7054b592011-06-22 14:46:42534 return false;
535
536 return true;
[email protected]adb2f3d12011-01-23 16:24:54537}
538
[email protected]5656f8a2011-11-17 16:12:58539void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
541 VLOG(20) << __FUNCTION__ << "()" << " download = "
542 << download->DebugString(false);
543
544 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32545 return;
[email protected]9ccbb372008-10-10 18:50:32546
[email protected]adb2f3d12011-01-23 16:24:54547 // TODO(rdsmith): DCHECK that we only pass through this point
548 // once per download. The natural way to do this is by a state
549 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56550
[email protected]adb2f3d12011-01-23 16:24:54551 // Confirm we're in the proper set of states to be here;
[email protected]9d7ef802011-02-25 19:03:35552 // in in_progress_, have all data, have a history handle, (validated or safe).
[email protected]c09a8fd2011-11-21 19:54:50553 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
554 DCHECK_EQ(1u, in_progress_.count(download->GetId()));
555 DCHECK(download->AllDataSaved());
556 DCHECK(download->GetDbHandle() != DownloadItem::kUninitializedHandle);
557 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54558
[email protected]c2918652011-11-01 18:50:23559 // Give the delegate a chance to override.
560 if (!delegate_->ShouldCompleteDownload(download))
561 return;
562
[email protected]adb2f3d12011-01-23 16:24:54563 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
564 << download->DebugString(false);
565
566 // Remove the id from in_progress
[email protected]c09a8fd2011-11-21 19:54:50567 in_progress_.erase(download->GetId());
[email protected]5f8589fe2011-08-17 20:58:39568 UpdateDownloadProgress(); // Reflect removal from in_progress_.
[email protected]adb2f3d12011-01-23 16:24:54569
[email protected]2588ea9d2011-08-22 20:59:53570 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54571
[email protected]f5920322011-03-24 20:34:16572 // Finish the download.
[email protected]48837962011-04-19 17:03:29573 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32574}
575
[email protected]fc03de22011-12-06 23:28:12576void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27577 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21578 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53579 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12580 active_downloads_.erase(download->GetId());
581 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27582}
583
[email protected]5656f8a2011-11-17 16:12:58584void DownloadManagerImpl::OnDownloadRenamedToFinalName(
585 int download_id,
586 const FilePath& full_path,
587 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50588 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16589 << " full_path = \"" << full_path.value() << "\""
590 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18591 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16592
[email protected]2e030682010-07-23 19:45:36593 DownloadItem* item = GetDownloadItem(download_id);
594 if (!item)
595 return;
[email protected]6cade212008-12-03 00:32:22596
[email protected]795b76a2011-12-14 16:52:53597 if (item->GetDangerType() == DownloadStateInfo::NOT_DANGEROUS ||
598 item->PromptUserForSaveLocation()) {
599 DCHECK_EQ(0, uniquifier)
600 << "We should not uniquify user supplied filenames or safe filenames "
601 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02602 }
603
[email protected]fabf36d22011-10-28 21:50:17604 BrowserThread::PostTask(
605 BrowserThread::FILE, FROM_HERE,
606 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50607 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32608
[email protected]f5920322011-03-24 20:34:16609 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50610 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32611
[email protected]f5920322011-03-24 20:34:16612 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53613 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29614}
615
[email protected]5656f8a2011-11-17 16:12:58616void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17617 DownloadItem* download = GetActiveDownload(download_id);
618 // A cancel at the right time could remove the download from the
619 // |active_downloads_| map before we get here.
620 if (!download)
621 return;
622
623 download->Cancel(true);
624}
625
[email protected]fc03de22011-12-06 23:28:12626void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20627 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20628
629 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50630 << " download = " << download->DebugString(true);
631
[email protected]93af2272011-09-21 18:29:17632 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21633 // This function is called from the DownloadItem, so DI state
634 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12635 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29636
[email protected]15d90ba2011-11-03 03:41:55637 if (file_manager_)
638 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29639}
640
[email protected]5656f8a2011-11-17 16:12:58641void DownloadManagerImpl::OnDownloadInterrupted(int32 download_id,
642 int64 size,
[email protected]0afff032012-01-06 20:55:00643 const std::string& hash_state,
[email protected]5656f8a2011-11-17 16:12:58644 InterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21645 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
646
647 DownloadItem* download = GetActiveDownload(download_id);
648 if (!download)
649 return;
650
[email protected]be76b7e2011-10-13 12:57:57651 VLOG(20) << __FUNCTION__ << "()"
652 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50653 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21654 << " size = " << size
655 << " download = " << download->DebugString(true);
656
[email protected]93af2272011-09-21 18:29:17657 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41658 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17659 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21660}
661
[email protected]5656f8a2011-11-17 16:12:58662DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26663 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
664 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26665 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21666 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26667
668 DownloadItem* download = it->second;
669
[email protected]47a881b2011-08-29 22:59:21670 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50671 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01672
[email protected]47a881b2011-08-29 22:59:21673 return download;
674}
[email protected]54610672011-07-18 18:24:43675
[email protected]5656f8a2011-11-17 16:12:58676void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17677 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
678 DCHECK(download);
679
680 // Clean up will happen when the history system create callback runs if we
681 // don't have a valid db_handle yet.
[email protected]c09a8fd2011-11-21 19:54:50682 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
683 in_progress_.erase(download->GetId());
684 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17685 UpdateDownloadProgress(); // Reflect removal from in_progress_.
686 delegate_->UpdateItemInPersistentStore(download);
687 }
688}
689
[email protected]5656f8a2011-11-17 16:12:58690content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
691 return delegate_;
692}
693
694void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17695 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35696 delegate_ = delegate;
697}
698
[email protected]5656f8a2011-11-17 16:12:58699void DownloadManagerImpl::UpdateDownloadProgress() {
[email protected]5f8589fe2011-08-17 20:58:39700 delegate_->DownloadProgressUpdated();
[email protected]6a7fb042010-02-01 16:30:47701}
702
[email protected]5656f8a2011-11-17 16:12:58703int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04704 const DownloadVector& pending_deletes) {
705 if (pending_deletes.empty())
706 return 0;
707
708 // Delete from internal maps.
709 for (DownloadVector::const_iterator it = pending_deletes.begin();
710 it != pending_deletes.end();
711 ++it) {
712 DownloadItem* download = *it;
713 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50714 history_downloads_.erase(download->GetDbHandle());
715 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04716 downloads_.erase(download);
717 }
718
719 // Tell observers to refresh their views.
720 NotifyModelChanged();
721
722 // Delete the download items themselves.
723 const int num_deleted = static_cast<int>(pending_deletes.size());
724 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
725 return num_deleted;
726}
727
[email protected]fc03de22011-12-06 23:28:12728void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
729 if (history_downloads_.find(download->GetDbHandle()) ==
730 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17731 return;
732
733 // Make history update.
[email protected]93af2272011-09-21 18:29:17734 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29735
736 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04737 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07738 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29739}
740
[email protected]5656f8a2011-11-17 16:12:58741int DownloadManagerImpl::RemoveDownloadsBetween(const base::Time remove_begin,
742 const base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53743 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29744
[email protected]a312a442010-12-15 23:40:33745 // All downloads visible to the user will be in the history,
746 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04747 DownloadVector pending_deletes;
748 for (DownloadMap::const_iterator it = history_downloads_.begin();
749 it != history_downloads_.end();
750 ++it) {
initial.commit09911bf2008-07-26 23:55:29751 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50752 if (download->GetStartTime() >= remove_begin &&
753 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04754 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12755 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28756 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29757 }
initial.commit09911bf2008-07-26 23:55:29758 }
[email protected]6d0146c2011-08-04 19:13:04759 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29760}
761
[email protected]5656f8a2011-11-17 16:12:58762int DownloadManagerImpl::RemoveDownloads(const base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59763 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29764}
765
[email protected]5656f8a2011-11-17 16:12:58766int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06767 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12768 // The null times make the date range unbounded.
769 return RemoveDownloadsBetween(base::Time(), base::Time());
770}
771
initial.commit09911bf2008-07-26 23:55:29772// Initiate a download of a specific URL. We send the request to the
773// ResourceDispatcherHost, and let it send us responses like a regular
774// download.
[email protected]5656f8a2011-11-17 16:12:58775void DownloadManagerImpl::DownloadUrl(const GURL& url,
776 const GURL& referrer,
777 const std::string& referrer_charset,
[email protected]bb81f382012-01-03 22:45:44778 WebContents* web_contents) {
[email protected]ae8945192010-07-20 16:56:26779 DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(),
[email protected]bb81f382012-01-03 22:45:44780 web_contents);
[email protected]6aa4a1c02010-01-15 18:49:58781}
782
[email protected]5656f8a2011-11-17 16:12:58783void DownloadManagerImpl::DownloadUrlToFile(const GURL& url,
784 const GURL& referrer,
785 const std::string& referrer_charset,
786 const DownloadSaveInfo& save_info,
[email protected]fbc5e5f92012-01-02 06:08:32787 WebContents* web_contents) {
[email protected]c79a0c02011-08-22 22:37:37788 ResourceDispatcherHost* resource_dispatcher_host =
[email protected]b4e74ee2012-01-10 19:31:57789 ResourceDispatcherHost::Get();
[email protected]443853c62011-12-22 19:22:41790
[email protected]ed24fad2011-05-10 22:44:01791 // We send a pointer to content::ResourceContext, instead of the usual
792 // reference, so that a copy of the object isn't made.
[email protected]fabf36d22011-10-28 21:50:17793 // base::Bind can't handle 7 args, so we use URLParams and RenderParams.
794 BrowserThread::PostTask(
795 BrowserThread::IO, FROM_HERE,
796 base::Bind(&BeginDownload,
797 URLParams(url, referrer), save_info, resource_dispatcher_host,
[email protected]fbc5e5f92012-01-02 06:08:32798 RenderParams(web_contents->GetRenderProcessHost()->GetID(),
799 web_contents->GetRenderViewHost()->routing_id()),
800 &web_contents->GetBrowserContext()->GetResourceContext()));
initial.commit09911bf2008-07-26 23:55:29801}
802
[email protected]5656f8a2011-11-17 16:12:58803void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29804 observers_.AddObserver(observer);
805 observer->ModelChanged();
806}
807
[email protected]5656f8a2011-11-17 16:12:58808void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29809 observers_.RemoveObserver(observer);
810}
811
[email protected]5656f8a2011-11-17 16:12:58812bool DownloadManagerImpl::IsDownloadProgressKnown() const {
[email protected]45f432e942011-10-25 18:17:22813 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02814 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50815 if (i->second->GetTotalBytes() <= 0)
[email protected]073ed7b2010-09-27 09:20:02816 return false;
817 }
818
819 return true;
820}
821
[email protected]5656f8a2011-11-17 16:12:58822int64 DownloadManagerImpl::GetInProgressDownloadCount() const {
[email protected]073ed7b2010-09-27 09:20:02823 return in_progress_.size();
824}
825
[email protected]5656f8a2011-11-17 16:12:58826int64 DownloadManagerImpl::GetReceivedDownloadBytes() const {
[email protected]073ed7b2010-09-27 09:20:02827 DCHECK(IsDownloadProgressKnown());
828 int64 received_bytes = 0;
[email protected]45f432e942011-10-25 18:17:22829 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02830 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50831 received_bytes += i->second->GetReceivedBytes();
[email protected]073ed7b2010-09-27 09:20:02832 }
833 return received_bytes;
834}
835
[email protected]5656f8a2011-11-17 16:12:58836int64 DownloadManagerImpl::GetTotalDownloadBytes() const {
[email protected]073ed7b2010-09-27 09:20:02837 DCHECK(IsDownloadProgressKnown());
838 int64 total_bytes = 0;
[email protected]45f432e942011-10-25 18:17:22839 for (DownloadMap::const_iterator i = in_progress_.begin();
[email protected]073ed7b2010-09-27 09:20:02840 i != in_progress_.end(); ++i) {
[email protected]c09a8fd2011-11-21 19:54:50841 total_bytes += i->second->GetTotalBytes();
[email protected]073ed7b2010-09-27 09:20:02842 }
843 return total_bytes;
844}
845
[email protected]5656f8a2011-11-17 16:12:58846void DownloadManagerImpl::FileSelected(const FilePath& path, void* params) {
[email protected]4cd82f72011-05-23 19:15:01847 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
848
849 int32* id_ptr = reinterpret_cast<int32*>(params);
850 DCHECK(id_ptr != NULL);
851 int32 download_id = *id_ptr;
852 delete id_ptr;
853
854 DownloadItem* download = GetActiveDownloadItem(download_id);
855 if (!download)
856 return;
857 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
858 << " download = " << download->DebugString(true);
859
[email protected]c09a8fd2011-11-21 19:54:50860 if (download->PromptUserForSaveLocation())
[email protected]7ae7c2cb2009-01-06 23:31:41861 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35862
[email protected]4cd82f72011-05-23 19:15:01863 // Make sure the initial file name is set only once.
864 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29865}
866
[email protected]5656f8a2011-11-17 16:12:58867void DownloadManagerImpl::FileSelectionCanceled(void* params) {
initial.commit09911bf2008-07-26 23:55:29868 // The user didn't pick a place to save the file, so need to cancel the
869 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01870 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
871 int32* id_ptr = reinterpret_cast<int32*>(params);
872 DCHECK(id_ptr != NULL);
873 int32 download_id = *id_ptr;
874 delete id_ptr;
875
876 DownloadItem* download = GetActiveDownloadItem(download_id);
877 if (!download)
878 return;
879
880 VLOG(20) << __FUNCTION__ << "()"
881 << " download = " << download->DebugString(true);
882
[email protected]93af2272011-09-21 18:29:17883 // TODO(ahendrickson) -- This currently has no effect, as the download is
884 // not put on the active list until the file selection is complete. Need
885 // to put it on the active list earlier in the process.
886 RemoveFromActiveList(download);
887
888 download->OffThreadCancel(file_manager_);
[email protected]4cd82f72011-05-23 19:15:01889}
890
initial.commit09911bf2008-07-26 23:55:29891// Operations posted to us from the history service ----------------------------
892
893// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25894// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58895void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25896 std::vector<DownloadPersistentStoreInfo>* entries) {
[email protected]d8472d92011-08-26 20:15:20897 // TODO(rdsmith): Remove this and related logic when
[email protected]a896ce32012-01-09 22:04:07898 // http://crbug.com/96627 is fixed.
[email protected]d8472d92011-08-26 20:15:20899 largest_db_handle_in_history_ = 0;
900
initial.commit09911bf2008-07-26 23:55:29901 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]fc03de22011-12-06 23:28:12902 DownloadItem* download = new DownloadItemImpl(
903 this, GetNextId(), entries->at(i));
[email protected]a896ce32012-01-09 22:04:07904 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]f04182f32010-12-10 19:12:07905 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50906 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50907 VLOG(20) << __FUNCTION__ << "()" << i << ">"
908 << " download = " << download->DebugString(true);
[email protected]d8472d92011-08-26 20:15:20909
[email protected]c09a8fd2011-11-21 19:54:50910 if (download->GetDbHandle() > largest_db_handle_in_history_)
911 largest_db_handle_in_history_ = download->GetDbHandle();
initial.commit09911bf2008-07-26 23:55:29912 }
[email protected]b0ab1d42010-02-24 19:29:28913 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48914 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29915}
916
[email protected]5656f8a2011-11-17 16:12:58917void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
918 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27919 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d2a8fb72010-01-21 05:31:42920
[email protected]a896ce32012-01-09 22:04:07921 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]1e9fe7ff2011-06-24 17:37:33922 // is fixed.
[email protected]2588ea9d2011-08-22 20:59:53923 CHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33924
[email protected]da4a5582011-10-17 19:08:06925 download_stats::RecordHistorySize(history_downloads_.size());
926
[email protected]c09a8fd2011-11-21 19:54:50927 DCHECK(download->GetDbHandle() == DownloadItem::kUninitializedHandle);
928 download->SetDbHandle(db_handle);
[email protected]5bcd73eb2011-03-23 21:14:02929
[email protected]a896ce32012-01-09 22:04:07930 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]d8472d92011-08-26 20:15:20931 // is fixed.
[email protected]a896ce32012-01-09 22:04:07932 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]c09a8fd2011-11-21 19:54:50933 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04934
935 // Show in the appropriate browser UI.
936 // This includes buttons to save or cancel, for a dangerous download.
937 ShowDownloadInBrowser(download);
938
939 // Inform interested objects about the new download.
940 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19941}
942
[email protected]2588ea9d2011-08-22 20:59:53943
[email protected]5656f8a2011-11-17 16:12:58944void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
945 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53946 if (save_page_downloads_.count(download_id)) {
947 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
948 } else if (active_downloads_.count(download_id)) {
949 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
950 }
951 // It's valid that we don't find a matching item, i.e. on shutdown.
952}
953
[email protected]f9a45b02011-06-30 23:49:19954// Once the new DownloadItem's creation info has been committed to the history
955// service, we associate the DownloadItem with the db handle, update our
956// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:58957void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
958 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:19959 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:45960 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:17961 if (!download)
[email protected]19420cc2011-07-18 17:43:45962 return;
[email protected]54610672011-07-18 18:24:43963
964 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
965 << " download_id = " << download_id
966 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:19967
[email protected]a896ce32012-01-09 22:04:07968 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:20969 int64 largest_handle = largest_db_handle_in_history_;
970 base::debug::Alias(&largest_handle);
[email protected]e5107ce2011-09-19 20:36:13971 int32 matching_item_download_id
972 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:50973 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:13974 base::debug::Alias(&matching_item_download_id);
975
[email protected]a896ce32012-01-09 22:04:07976 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:20977
[email protected]f9a45b02011-06-30 23:49:19978 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:29979
[email protected]93af2272011-09-21 18:29:17980 // If the download is still in progress, try to complete it.
981 //
982 // Otherwise, download has been cancelled or interrupted before we've
983 // received the DB handle. We post one final message to the history
984 // service so that it can be properly in sync with the DownloadItem's
985 // completion status, and also inform any observers so that they get
986 // more than just the start notification.
987 if (download->IsInProgress()) {
988 MaybeCompleteDownload(download);
989 } else {
[email protected]a896ce32012-01-09 22:04:07990 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]93af2272011-09-21 18:29:17991 // is fixed.
992 CHECK(download->IsCancelled())
993 << " download = " << download->DebugString(true);
994 in_progress_.erase(download_id);
995 active_downloads_.erase(download_id);
996 delegate_->UpdateItemInPersistentStore(download);
997 download->UpdateObservers();
998 }
initial.commit09911bf2008-07-26 23:55:29999}
1000
[email protected]5656f8a2011-11-17 16:12:581001void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]8ddbd66a2010-05-21 16:38:341002 // The 'contents' may no longer exist if the user closed the tab before we
[email protected]99cb7f82011-07-28 17:27:261003 // get this start completion event.
[email protected]2a6bc3e2011-12-28 23:51:331004 WebContents* content = download->GetTabContents();
[email protected]99cb7f82011-07-28 17:27:261005
1006 // If the contents no longer exists, we ask the embedder to suggest another
1007 // tab.
[email protected]da1a27b2011-07-29 23:16:331008 if (!content)
[email protected]ef9572e2012-01-04 22:14:121009 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:531010
[email protected]0bfbf882011-12-22 18:19:271011 if (content && content->GetDelegate())
1012 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531013}
1014
[email protected]5656f8a2011-11-17 16:12:581015int DownloadManagerImpl::InProgressCount() const {
1016 return static_cast<int>(in_progress_.size());
1017}
1018
[email protected]6cade212008-12-03 00:32:221019// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581020void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411021 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381022}
[email protected]b0ab1d42010-02-24 19:29:281023
[email protected]5656f8a2011-11-17 16:12:581024void DownloadManagerImpl::NotifyModelChanged() {
[email protected]b0ab1d42010-02-24 19:29:281025 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged());
1026}
1027
[email protected]5656f8a2011-11-17 16:12:581028DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011029 // The |history_downloads_| map is indexed by the download's db_handle,
1030 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071031 for (DownloadMap::iterator it = history_downloads_.begin();
1032 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361033 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501034 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361035 return item;
1036 }
1037 return NULL;
1038}
1039
[email protected]5656f8a2011-11-17 16:12:581040DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361041 if (ContainsKey(active_downloads_, download_id))
1042 return active_downloads_[download_id];
1043 return NULL;
[email protected]4cd82f72011-05-23 19:15:011044}
1045
[email protected]57fd1252010-12-23 17:24:091046// Confirm that everything in all maps is also in |downloads_|, and that
1047// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581048void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071049#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091050 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041051 const DownloadMap* input_maps[] = {&active_downloads_,
1052 &history_downloads_,
1053 &save_page_downloads_};
1054 DownloadSet active_set, history_set, save_page_set;
1055 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1056 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091057 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1058 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041059 it != input_maps[i]->end(); ++it) {
1060 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071061 }
1062 }
[email protected]57fd1252010-12-23 17:24:091063
1064 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091065 DownloadSet downloads_union;
1066 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1067 DownloadSet remainder;
1068 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1069 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1070 downloads_.begin(), downloads_.end(),
1071 insert_it);
1072 DCHECK(remainder.empty());
1073 std::insert_iterator<DownloadSet>
1074 insert_union(downloads_union, downloads_union.end());
1075 std::set_union(downloads_union.begin(), downloads_union.end(),
1076 all_sets[i]->begin(), all_sets[i]->end(),
1077 insert_union);
1078 }
1079
1080 // Is everything in downloads_ present in one of the other sets?
1081 DownloadSet remainder;
1082 std::insert_iterator<DownloadSet>
1083 insert_remainder(remainder, remainder.begin());
1084 std::set_difference(downloads_.begin(), downloads_.end(),
1085 downloads_union.begin(), downloads_union.end(),
1086 insert_remainder);
1087 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071088#endif
1089}
1090
[email protected]6d0146c2011-08-04 19:13:041091// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531092// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041093// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531094// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1095// that the history event is update regardless of the order in which these two
1096// events complete.
[email protected]6d0146c2011-08-04 19:13:041097// If something removes the download item from the download manager (Remove,
1098// Shutdown) the result will be that the SavePage system will not be able to
1099// properly update the download item (which no longer exists) or the download
1100// history, but the action will complete properly anyway. This may lead to the
1101// history entry being wrong on a reload of chrome (specifically in the case of
1102// Initiation -> History Callback -> Removal -> Completion), but there's no way
1103// to solve that without canceling on Remove (which would then update the DB).
1104
[email protected]5656f8a2011-11-17 16:12:581105void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1106 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1108
1109 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1110 // This can happen if the download manager is shutting down and all maps
1111 // have been cleared.
1112 if (it == save_page_downloads_.end())
1113 return;
1114
1115 DownloadItem* download = it->second;
1116 if (!download) {
1117 NOTREACHED();
1118 return;
1119 }
1120
[email protected]a896ce32012-01-09 22:04:071121 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201122 int64 largest_handle = largest_db_handle_in_history_;
1123 base::debug::Alias(&largest_handle);
[email protected]a896ce32012-01-09 22:04:071124 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201125
[email protected]6d0146c2011-08-04 19:13:041126 AddDownloadItemToHistory(download, db_handle);
1127
1128 // Finalize this download if it finished before the history callback.
1129 if (!download->IsInProgress())
1130 SavePageDownloadFinished(download);
1131}
1132
[email protected]5656f8a2011-11-17 16:12:581133void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]c09a8fd2011-11-21 19:54:501134 if (download->GetDbHandle() != DownloadItem::kUninitializedHandle) {
[email protected]2588ea9d2011-08-22 20:59:531135 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501136 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1137 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041138
1139 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071140 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041141 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531142 content::Source<DownloadManager>(this),
1143 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041144 }
1145}
[email protected]da4a5582011-10-17 19:08:061146
[email protected]fc03de22011-12-06 23:28:121147void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061148 delegate_->UpdateItemInPersistentStore(download);
1149 int num_unopened = 0;
1150 for (DownloadMap::iterator it = history_downloads_.begin();
1151 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501152 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061153 ++num_unopened;
1154 }
1155 download_stats::RecordOpensOutstanding(num_unopened);
1156}
[email protected]5656f8a2011-11-17 16:12:581157
1158void DownloadManagerImpl::SetFileManager(DownloadFileManager* file_manager) {
1159 file_manager_ = file_manager;
1160}