blob: cf9ae3a8ccfa5cc6452b485e79c4b9235746eaaf [file] [log] [blame]
[email protected]0afff032012-01-06 20:55:001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]5656f8a2011-11-17 16:12:585#include "content/browser/download/download_manager_impl.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]e7557f172011-08-19 23:42:017#include <iterator>
8
[email protected]eda58402011-09-21 19:32:029#include "base/bind.h"
[email protected]2041cf342010-02-19 03:15:5910#include "base/callback.h"
[email protected]c6944272012-01-06 22:12:2811#include "base/debug/alias.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/file_util.h"
[email protected]503d03872011-05-06 08:36:2613#include "base/i18n/case_conversion.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/logging.h"
[email protected]7286e3fc2011-07-19 22:13:2415#include "base/stl_util.h"
[email protected]eda58402011-09-21 19:32:0216#include "base/stringprintf.h"
17#include "base/synchronization/lock.h"
18#include "base/sys_string_conversions.h"
[email protected]d2a8fb72010-01-21 05:31:4219#include "build/build_config.h"
[email protected]71bf3f5e2011-08-15 21:05:2220#include "content/browser/download/download_create_info.h"
21#include "content/browser/download/download_file_manager.h"
[email protected]c09a8fd2011-11-21 19:54:5022#include "content/browser/download/download_item_impl.h"
[email protected]da4a5582011-10-17 19:08:0623#include "content/browser/download/download_stats.h"
[email protected]b3c41c0b2012-03-06 15:48:3224#include "content/browser/renderer_host/render_view_host_impl.h"
[email protected]ea114722012-03-12 01:11:2525#include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
[email protected]93ddb3c2012-04-11 21:44:2926#include "content/browser/web_contents/web_contents_impl.h"
[email protected]ccb797302011-12-15 16:55:1127#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4928#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4429#include "content/public/browser/content_browser_client.h"
[email protected]bf3b08a2012-03-08 01:52:3430#include "content/public/browser/download_interrupt_reasons.h"
[email protected]1bd0ef12011-10-20 05:24:1731#include "content/public/browser/download_manager_delegate.h"
[email protected]8da82ea2012-03-11 22:16:5232#include "content/public/browser/download_persistent_store_info.h"
[email protected]c5a5c0842012-05-04 20:05:1433#include "content/public/browser/download_url_parameters.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"
[email protected]c5a5c0842012-05-04 20:05:1438#include "net/base/load_flags.h"
[email protected]27678b2a2012-02-04 22:09:1439#include "net/base/upload_data.h"
initial.commit09911bf2008-07-26 23:55:2940
[email protected]631bb742011-11-02 11:29:3941using content::BrowserThread;
[email protected]98e814062012-01-27 00:35:4242using content::DownloadId;
[email protected]e582fdd2011-12-20 16:48:1743using content::DownloadItem;
[email protected]8da82ea2012-03-11 22:16:5244using content::DownloadPersistentStoreInfo;
[email protected]ea114722012-03-12 01:11:2545using content::ResourceDispatcherHostImpl;
[email protected]2a6bc3e2011-12-28 23:51:3346using content::WebContents;
[email protected]631bb742011-11-02 11:29:3947
[email protected]a0ce3282011-08-19 20:49:5248namespace {
49
[email protected]c5a5c0842012-05-04 20:05:1450void BeginDownload(content::DownloadUrlParameters* params) {
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
52 // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and
53 // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so
54 // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4.
55 content::ResourceDispatcherHostImpl* resource_dispatcher_host =
56 static_cast<content::ResourceDispatcherHostImpl*>(
57 params->resource_dispatcher_host());
58 scoped_ptr<net::URLRequest> request(new net::URLRequest(
59 params->url(), resource_dispatcher_host));
60 request->set_referrer(params->referrer().spec());
61 request->set_load_flags(request->load_flags() | params->load_flags());
62 request->set_method(params->method());
63 if (!params->post_body().empty())
64 request->AppendBytesToUpload(params->post_body().data(),
65 params->post_body().size());
66 if (params->post_id() >= 0) {
[email protected]27678b2a2012-02-04 22:09:1467 // The POST in this case does not have an actual body, and only works
68 // when retrieving data from cache. This is done because we don't want
69 // to do a re-POST without user consent, and currently don't have a good
70 // plan on how to display the UI for that.
[email protected]c5a5c0842012-05-04 20:05:1471 DCHECK(params->prefer_cache());
72 DCHECK(params->method() == "POST");
[email protected]27678b2a2012-02-04 22:09:1473 scoped_refptr<net::UploadData> upload_data = new net::UploadData();
[email protected]c5a5c0842012-05-04 20:05:1474 upload_data->set_identifier(params->post_id());
[email protected]27678b2a2012-02-04 22:09:1475 request->set_upload(upload_data);
76 }
[email protected]c5a5c0842012-05-04 20:05:1477 for (content::DownloadUrlParameters::RequestHeadersType::const_iterator iter
78 = params->request_headers_begin();
79 iter != params->request_headers_end();
80 ++iter) {
81 request->SetExtraRequestHeaderByName(
82 iter->first, iter->second, false/*overwrite*/);
83 }
[email protected]c79a0c02011-08-22 22:37:3784 resource_dispatcher_host->BeginDownload(
[email protected]ea114722012-03-12 01:11:2585 request.Pass(),
[email protected]a53e2f92012-05-15 15:27:0686 params->content_initiated(),
[email protected]c5a5c0842012-05-04 20:05:1487 params->resource_context(),
88 params->render_process_host_id(),
89 params->render_view_host_routing_id(),
90 params->prefer_cache(),
91 params->save_info(),
92 params->callback());
[email protected]a0ce3282011-08-19 20:49:5293}
94
[email protected]33d22102012-01-25 17:46:5395class MapValueIteratorAdapter {
96 public:
97 explicit MapValueIteratorAdapter(
98 base::hash_map<int64, DownloadItem*>::const_iterator iter)
99 : iter_(iter) {
100 }
101 ~MapValueIteratorAdapter() {}
102
103 DownloadItem* operator*() { return iter_->second; }
104
105 MapValueIteratorAdapter& operator++() {
106 ++iter_;
107 return *this;
108 }
109
110 bool operator!=(const MapValueIteratorAdapter& that) const {
111 return iter_ != that.iter_;
112 }
113
114 private:
115 base::hash_map<int64, DownloadItem*>::const_iterator iter_;
116 // Allow copy and assign.
117};
118
[email protected]5948e1a2012-03-10 00:19:18119void EnsureNoPendingDownloadsOnFile(scoped_refptr<DownloadFileManager> dfm,
120 bool* result) {
121 if (dfm->NumberOfActiveDownloads())
122 *result = false;
123 BrowserThread::PostTask(
124 BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure());
125}
126
[email protected]0a5c9112012-03-12 17:49:02127void EnsureNoPendingDownloadJobsOnIO(bool* result) {
[email protected]5948e1a2012-03-10 00:19:18128 scoped_refptr<DownloadFileManager> download_file_manager =
[email protected]ea114722012-03-12 01:11:25129 ResourceDispatcherHostImpl::Get()->download_file_manager();
[email protected]5948e1a2012-03-10 00:19:18130 BrowserThread::PostTask(
131 BrowserThread::FILE, FROM_HERE,
132 base::Bind(&EnsureNoPendingDownloadsOnFile,
133 download_file_manager, result));
134}
135
[email protected]a0ce3282011-08-19 20:49:52136} // namespace
137
[email protected]99907362012-01-11 05:41:40138namespace content {
139
140// static
141DownloadManager* DownloadManager::Create(
[email protected]ef17c9a2012-02-09 05:08:09142 content::DownloadManagerDelegate* delegate,
143 net::NetLog* net_log) {
144 return new DownloadManagerImpl(delegate, net_log);
[email protected]99907362012-01-11 05:41:40145}
146
[email protected]5948e1a2012-03-10 00:19:18147bool DownloadManager::EnsureNoPendingDownloadsForTesting() {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
149 bool result = true;
150 BrowserThread::PostTask(
151 BrowserThread::IO, FROM_HERE,
[email protected]0a5c9112012-03-12 17:49:02152 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result));
[email protected]5948e1a2012-03-10 00:19:18153 MessageLoop::current()->Run();
154 return result;
155}
156
[email protected]99907362012-01-11 05:41:40157} // namespace content
158
[email protected]5656f8a2011-11-17 16:12:58159DownloadManagerImpl::DownloadManagerImpl(
[email protected]ef17c9a2012-02-09 05:08:09160 content::DownloadManagerDelegate* delegate,
161 net::NetLog* net_log)
[email protected]5656f8a2011-11-17 16:12:58162 : shutdown_needed_(false),
163 browser_context_(NULL),
164 file_manager_(NULL),
[email protected]5656f8a2011-11-17 16:12:58165 delegate_(delegate),
[email protected]ef17c9a2012-02-09 05:08:09166 net_log_(net_log) {
initial.commit09911bf2008-07-26 23:55:29167}
168
[email protected]5656f8a2011-11-17 16:12:58169DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13170 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29171}
172
[email protected]5656f8a2011-11-17 16:12:58173DownloadId DownloadManagerImpl::GetNextId() {
[email protected]98e814062012-01-27 00:35:42174 return delegate_->GetNextId();
[email protected]2909e342011-10-29 00:46:53175}
176
[email protected]fc03de22011-12-06 23:28:12177bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
178 return delegate_->ShouldOpenDownload(item);
179}
180
181bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
182 return delegate_->ShouldOpenFileBasedOnExtension(path);
183}
184
[email protected]5656f8a2011-11-17 16:12:58185void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50186 VLOG(20) << __FUNCTION__ << "()"
187 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13188 if (!shutdown_needed_)
189 return;
190 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29191
[email protected]75e51b52012-02-04 16:57:54192 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
[email protected]fb4f8d902011-09-16 06:07:08193 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13194
195 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18196 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17197 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
198 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13199 }
initial.commit09911bf2008-07-26 23:55:29200
[email protected]f04182f32010-12-10 19:12:07201 AssertContainersConsistent();
202
203 // Go through all downloads in downloads_. Dangerous ones we need to
204 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09205 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07206 DownloadItem* download = *it;
207
208 // Save iterator from potential erases in this set done by called code.
209 // Iterators after an erasure point are still valid for lists and
210 // associative containers such as sets.
211 it++;
212
[email protected]c09a8fd2011-11-21 19:54:50213 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29214 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07215 // The user hasn't accepted it, so we need to remove it
216 // from the disk. This may or may not result in it being
217 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12218 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07219 // removes and deletes it if it's known to the history service)
220 // so the only thing we know after calling this function is that
221 // the download was deleted if-and-only-if it was removed
222 // from all queues.
[email protected]303077002011-04-19 23:21:01223 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26224 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17225 download->Cancel(false);
226 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29227 }
228 }
229
[email protected]f04182f32010-12-10 19:12:07230 // At this point, all dangerous downloads have had their files removed
231 // and all in progress downloads have been cancelled. We can now delete
232 // anything left.
[email protected]9ccbb372008-10-10 18:50:32233
[email protected]5cd11b6e2011-06-10 20:30:59234 // Copy downloads_ to separate container so as not to set off checks
235 // in DownloadItem destruction.
236 DownloadSet downloads_to_delete;
237 downloads_to_delete.swap(downloads_);
238
[email protected]70850c72011-01-11 17:31:27239 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59240 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59241 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29242
[email protected]41f558fb2012-01-09 22:59:58243 // We'll have nothing more to report to the observers after this point.
244 observers_.Clear();
245
[email protected]6d0146c2011-08-04 19:13:04246 DCHECK(save_page_downloads_.empty());
247
initial.commit09911bf2008-07-26 23:55:29248 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53249 delegate_->Shutdown();
initial.commit09911bf2008-07-26 23:55:29250}
251
[email protected]5656f8a2011-11-17 16:12:58252void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04253 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57254 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58255
[email protected]f04182f32010-12-10 19:12:07256 for (DownloadMap::iterator it = history_downloads_.begin();
257 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50258 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20259 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57260 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58261 }
[email protected]6aa4a1c02010-01-15 18:49:58262}
263
[email protected]5656f8a2011-11-17 16:12:58264void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04265 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57266 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34267
[email protected]f04182f32010-12-10 19:12:07268 for (DownloadMap::iterator it = history_downloads_.begin();
269 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50270 if (!it->second->IsTemporary() &&
271 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57272 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34273 }
[email protected]8ddbd66a2010-05-21 16:38:34274}
275
[email protected]5656f8a2011-11-17 16:12:58276void DownloadManagerImpl::SearchDownloads(const string16& query,
277 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26278 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42279
[email protected]f04182f32010-12-10 19:12:07280 for (DownloadMap::iterator it = history_downloads_.begin();
281 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42282 DownloadItem* download_item = it->second;
283
[email protected]c09a8fd2011-11-21 19:54:50284 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42285 continue;
286
287 // Display Incognito downloads only in Incognito window, and vice versa.
288 // The Incognito Downloads page will get the list of non-Incognito downloads
289 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50290 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42291 continue;
292
293 if (download_item->MatchesQuery(query_lower))
294 result->push_back(download_item);
295 }
[email protected]d3b12902010-08-16 23:39:42296}
297
initial.commit09911bf2008-07-26 23:55:29298// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58299bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03300 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29301 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
302 shutdown_needed_ = true;
303
[email protected]6d0c9fb2011-08-22 19:26:03304 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46305
[email protected]ea114722012-03-12 01:11:25306 // In test mode, there may be no ResourceDispatcherHostImpl. In this case
307 // it's safe to avoid setting |file_manager_| because we only call a small
308 // set of functions, none of which need it.
309 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
[email protected]b39e7a88b2012-01-10 21:43:17310 if (rdh) {
311 file_manager_ = rdh->download_file_manager();
312 DCHECK(file_manager_);
313 }
initial.commit09911bf2008-07-26 23:55:29314
initial.commit09911bf2008-07-26 23:55:29315 return true;
316}
317
[email protected]aa9881c2011-08-15 18:01:12318// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58319void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35321
[email protected]aa9881c2011-08-15 18:01:12322 if (delegate_->ShouldStartDownload(download_id))
323 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35324}
325
[email protected]5656f8a2011-11-17 16:12:58326void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
328 for (DownloadMap::iterator it = history_downloads_.begin();
329 it != history_downloads_.end(); ++it) {
330 CheckForFileRemoval(it->second);
331 }
332}
333
[email protected]5656f8a2011-11-17 16:12:58334void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
336 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50337 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48338 BrowserThread::PostTask(
339 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58340 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50341 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17342 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48343 }
344}
345
[email protected]5656f8a2011-11-17 16:12:58346void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48347 int64 db_handle, const FilePath& path) {
348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
349 if (!file_util::PathExists(path)) {
350 BrowserThread::PostTask(
351 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58352 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
353 this,
354 db_handle));
[email protected]9fc114672011-06-15 08:17:48355 }
356}
357
[email protected]5656f8a2011-11-17 16:12:58358void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
360 DownloadMap::iterator it = history_downloads_.find(db_handle);
361 if (it != history_downloads_.end()) {
362 DownloadItem* download_item = it->second;
363 download_item->OnDownloadedFileRemoved();
364 }
365}
366
[email protected]443853c62011-12-22 19:22:41367void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29369
[email protected]4cd82f72011-05-23 19:15:01370 DownloadItem* download = GetActiveDownloadItem(download_id);
371 if (!download)
372 return;
373
374 VLOG(20) << __FUNCTION__ << "()"
375 << " download = " << download->DebugString(true);
376
[email protected]c09a8fd2011-11-21 19:54:50377 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01378
[email protected]c09a8fd2011-11-21 19:54:50379 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29380 // We must ask the user for the place to put the download.
[email protected]a62d42902012-01-24 17:24:38381 WebContents* contents = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:26382
[email protected]795b76a2011-12-14 16:52:53383 FilePath target_path;
384 // If |download| is a potentially dangerous file, then |suggested_path|
385 // contains the intermediate name instead of the final download
386 // filename. The latter is GetTargetName().
[email protected]a62d42902012-01-24 17:24:38387 if (download->GetDangerType() !=
388 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
[email protected]795b76a2011-12-14 16:52:53389 target_path = suggested_path.DirName().Append(download->GetTargetName());
390 else
391 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26392
[email protected]795b76a2011-12-14 16:52:53393 delegate_->ChooseDownloadPath(contents, target_path,
[email protected]84d57412012-03-03 08:59:55394 download_id);
[email protected]f5920322011-03-24 20:34:16395 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]75e51b52012-02-04 16:57:54396 SelectFileDialogDisplayed(this, download_id));
initial.commit09911bf2008-07-26 23:55:29397 } else {
398 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01399 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29400 }
401}
402
[email protected]37757c62011-12-20 20:07:12403content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58404 return browser_context_;
405}
406
407FilePath DownloadManagerImpl::LastDownloadPath() {
408 return last_download_path_;
409}
410
[email protected]ef17c9a2012-02-09 05:08:09411net::BoundNetLog DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41412 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
414
[email protected]ef17c9a2012-02-09 05:08:09415 net::BoundNetLog bound_net_log =
416 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]c09a8fd2011-11-21 19:54:50417 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29418 this, *info, new DownloadRequestHandle(request_handle),
[email protected]ef17c9a2012-02-09 05:08:09419 browser_context_->IsOffTheRecord(), bound_net_log);
[email protected]2909e342011-10-29 00:46:53420 int32 download_id = info->download_id.local();
[email protected]d8472d92011-08-26 20:15:20421
[email protected]0634626a2012-05-03 19:04:26422 DCHECK(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29423 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01424 active_downloads_[download_id] = download;
[email protected]ef17c9a2012-02-09 05:08:09425
426 return bound_net_log;
[email protected]c2e76012010-12-23 21:10:29427}
428
[email protected]fc03de22011-12-06 23:28:12429DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
430 const FilePath& main_file_path,
431 const GURL& page_url,
432 bool is_otr,
[email protected]6474b112012-05-04 19:35:27433 const std::string& mime_type,
[email protected]fc03de22011-12-06 23:28:12434 DownloadItem::Observer* observer) {
[email protected]ef17c9a2012-02-09 05:08:09435 net::BoundNetLog bound_net_log =
436 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12437 DownloadItem* download = new DownloadItemImpl(
[email protected]6474b112012-05-04 19:35:27438 this,
439 main_file_path,
440 page_url,
441 is_otr,
442 GetNextId(),
443 mime_type,
444 bound_net_log);
[email protected]fc03de22011-12-06 23:28:12445
446 download->AddObserver(observer);
447
448 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
449 downloads_.insert(download);
450 save_page_downloads_[download->GetId()] = download;
451
452 // Will notify the observer in the callback.
453 delegate_->AddItemToPersistentStore(download);
454
455 return download;
456}
457
[email protected]795b76a2011-12-14 16:52:53458// For non-safe downloads with no prompting, |chosen_file| is the intermediate
459// path for saving the in-progress download. The final target filename for these
460// is |download->GetTargetName()|. For all other downloads (non-safe downloads
461// for which we have prompted for a save location, and all safe downloads),
462// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58463void DownloadManagerImpl::ContinueDownloadWithPath(
464 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01466 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39467
[email protected]c09a8fd2011-11-21 19:54:50468 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29469
[email protected]70850c72011-01-11 17:31:27470 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01471 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27472
[email protected]4cd82f72011-05-23 19:15:01473 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20474 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01475 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01476
477 VLOG(20) << __FUNCTION__ << "()"
478 << " download = " << download->DebugString(true);
479
[email protected]adb2f3d12011-01-23 16:24:54480 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16481 FilePath download_path;
[email protected]385e93182012-01-30 17:11:03482 if (download->GetDangerType() !=
483 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
484 if (download->PromptUserForSaveLocation()) {
485 // When we prompt the user, we overwrite the FullPath with what the user
486 // wanted to use. Construct a file path using the previously determined
487 // intermediate filename and the new path.
488 // TODO(asanka): This can trample an in-progress download in the new
489 // target directory if it was using the same intermediate name.
490 FilePath file_name = download->GetSuggestedPath().BaseName();
491 download_path = download->GetFullPath().DirName().Append(file_name);
492 } else {
493 // The download's name is already set to an intermediate name, so no need
494 // to override.
495 download_path = download->GetFullPath();
496 }
497 } else {
498 // The download is a safe download. We need to rename it to its
499 // intermediate path. The final name after user confirmation will be set
500 // from DownloadItem::OnDownloadCompleting.
501 download_path = delegate_->GetIntermediatePath(download->GetFullPath());
502 }
[email protected]594cd7d2010-07-21 03:23:56503
[email protected]f5920322011-03-24 20:34:16504 BrowserThread::PostTask(
505 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17506 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12507 file_manager_, download->GetGlobalId(),
508 download_path));
[email protected]f5920322011-03-24 20:34:16509
510 download->Rename(download_path);
511
[email protected]2588ea9d2011-08-22 20:59:53512 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29513}
514
[email protected]443853c62011-12-22 19:22:41515void DownloadManagerImpl::UpdateDownload(int32 download_id,
516 int64 bytes_so_far,
517 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00518 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
520 DownloadMap::iterator it = active_downloads_.find(download_id);
521 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29522 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26523 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41524 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]2588ea9d2011-08-22 20:59:53525 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27526 }
initial.commit09911bf2008-07-26 23:55:29527 }
528}
529
[email protected]5656f8a2011-11-17 16:12:58530void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
531 int64 size,
532 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54533 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50534 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
535 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35536 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32537
[email protected]c4f02c42011-01-24 21:55:06538 // If it's not in active_downloads_, that means it was cancelled; just
539 // ignore the notification.
540 if (active_downloads_.count(download_id) == 0)
541 return;
542
[email protected]adb2f3d12011-01-23 16:24:54543 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37544 download->OnAllDataSaved(size, hash);
[email protected]b09f1282011-09-14 00:37:45545
[email protected]fc03de22011-12-06 23:28:12546 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54547}
[email protected]9ccbb372008-10-10 18:50:32548
[email protected]fc03de22011-12-06 23:28:12549void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]c09a8fd2011-11-21 19:54:50550 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]0634626a2012-05-03 19:04:26551 DCHECK(!ContainsKey(downloads_, download));
552 DCHECK(!ContainsKey(active_downloads_, download->GetId()));
[email protected]0634626a2012-05-03 19:04:26553 DCHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17554 return;
555 }
556
557 // Should be in downloads_ if we're not REMOVING.
558 CHECK(ContainsKey(downloads_, download));
559
560 // Check history_downloads_ consistency.
[email protected]5009b7a2012-02-21 18:47:03561 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50562 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17563 } else {
[email protected]fc03de22011-12-06 23:28:12564 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17565 it != history_downloads_.end(); ++it) {
[email protected]0634626a2012-05-03 19:04:26566 DCHECK(it->second != download);
[email protected]7d413112011-06-16 18:50:17567 }
568 }
569
[email protected]c09a8fd2011-11-21 19:54:50570 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34571 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50572 if (ContainsKey(active_downloads_, download->GetId())) {
[email protected]5009b7a2012-02-21 18:47:03573 if (download->IsPersisted())
[email protected]c09a8fd2011-11-21 19:54:50574 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
575 if (DownloadItem::IN_PROGRESS != download->GetState())
576 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07577 }
[email protected]c09a8fd2011-11-21 19:54:50578 if (DownloadItem::IN_PROGRESS == download->GetState())
579 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59580}
581
[email protected]5656f8a2011-11-17 16:12:58582bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54583 // If we don't have all the data, the download is not ready for
584 // completion.
[email protected]c09a8fd2011-11-21 19:54:50585 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54586 return false;
[email protected]6a7fb042010-02-01 16:30:47587
[email protected]9d7ef802011-02-25 19:03:35588 // If the download is dangerous, but not yet validated, it's not ready for
589 // completion.
[email protected]c09a8fd2011-11-21 19:54:50590 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35591 return false;
592
[email protected]adb2f3d12011-01-23 16:24:54593 // If the download isn't active (e.g. has been cancelled) it's not
594 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50595 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54596 return false;
597
598 // If the download hasn't been inserted into the history system
599 // (which occurs strictly after file name determination, intermediate
600 // file rename, and UI display) then it's not ready for completion.
[email protected]5009b7a2012-02-21 18:47:03601 if (!download->IsPersisted())
[email protected]7054b592011-06-22 14:46:42602 return false;
603
604 return true;
[email protected]adb2f3d12011-01-23 16:24:54605}
606
[email protected]6474b112012-05-04 19:35:27607// When SavePackage downloads MHTML to GData (see
608// SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
609// does for non-SavePackage downloads, but SavePackage downloads never satisfy
610// IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
611// DownloadItem::UpdateObservers() when the upload completes so that SavePackage
612// notices that the upload has completed and runs its normal Finish() pathway.
613// MaybeCompleteDownload() is never the mechanism by which SavePackage completes
614// downloads. SavePackage always uses its own Finish() to mark downloads
615// complete.
616
[email protected]5656f8a2011-11-17 16:12:58617void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54618 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
619 VLOG(20) << __FUNCTION__ << "()" << " download = "
620 << download->DebugString(false);
621
622 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32623 return;
[email protected]9ccbb372008-10-10 18:50:32624
[email protected]adb2f3d12011-01-23 16:24:54625 // TODO(rdsmith): DCHECK that we only pass through this point
626 // once per download. The natural way to do this is by a state
627 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56628
[email protected]adb2f3d12011-01-23 16:24:54629 // Confirm we're in the proper set of states to be here;
[email protected]550520f2012-05-14 20:58:48630 // have all data, have a history handle, (validated or safe).
631 DCHECK(download->IsInProgress());
[email protected]c09a8fd2011-11-21 19:54:50632 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
[email protected]c09a8fd2011-11-21 19:54:50633 DCHECK(download->AllDataSaved());
[email protected]5009b7a2012-02-21 18:47:03634 DCHECK(download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50635 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54636
[email protected]c2918652011-11-01 18:50:23637 // Give the delegate a chance to override.
638 if (!delegate_->ShouldCompleteDownload(download))
639 return;
640
[email protected]adb2f3d12011-01-23 16:24:54641 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
642 << download->DebugString(false);
643
[email protected]2588ea9d2011-08-22 20:59:53644 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54645
[email protected]f5920322011-03-24 20:34:16646 // Finish the download.
[email protected]48837962011-04-19 17:03:29647 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32648}
649
[email protected]fc03de22011-12-06 23:28:12650void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21652 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53653 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12654 active_downloads_.erase(download->GetId());
655 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27656}
657
[email protected]5656f8a2011-11-17 16:12:58658void DownloadManagerImpl::OnDownloadRenamedToFinalName(
659 int download_id,
660 const FilePath& full_path,
661 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50662 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16663 << " full_path = \"" << full_path.value() << "\""
664 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18665 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16666
[email protected]2e030682010-07-23 19:45:36667 DownloadItem* item = GetDownloadItem(download_id);
668 if (!item)
669 return;
[email protected]6cade212008-12-03 00:32:22670
[email protected]a62d42902012-01-24 17:24:38671 if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
[email protected]795b76a2011-12-14 16:52:53672 item->PromptUserForSaveLocation()) {
673 DCHECK_EQ(0, uniquifier)
674 << "We should not uniquify user supplied filenames or safe filenames "
675 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02676 }
677
[email protected]fabf36d22011-10-28 21:50:17678 BrowserThread::PostTask(
679 BrowserThread::FILE, FROM_HERE,
680 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50681 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32682
[email protected]f5920322011-03-24 20:34:16683 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50684 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32685
[email protected]f5920322011-03-24 20:34:16686 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53687 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29688}
689
[email protected]5656f8a2011-11-17 16:12:58690void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17691 DownloadItem* download = GetActiveDownload(download_id);
692 // A cancel at the right time could remove the download from the
693 // |active_downloads_| map before we get here.
694 if (!download)
695 return;
696
697 download->Cancel(true);
698}
699
[email protected]fc03de22011-12-06 23:28:12700void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20701 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20702
703 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50704 << " download = " << download->DebugString(true);
705
[email protected]93af2272011-09-21 18:29:17706 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21707 // This function is called from the DownloadItem, so DI state
708 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12709 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29710
[email protected]15d90ba2011-11-03 03:41:55711 if (file_manager_)
712 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29713}
714
[email protected]bf3b08a2012-03-08 01:52:34715void DownloadManagerImpl::OnDownloadInterrupted(
716 int32 download_id,
717 int64 size,
718 const std::string& hash_state,
719 content::DownloadInterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21720 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
721
722 DownloadItem* download = GetActiveDownload(download_id);
723 if (!download)
724 return;
725
[email protected]be76b7e2011-10-13 12:57:57726 VLOG(20) << __FUNCTION__ << "()"
727 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50728 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21729 << " size = " << size
730 << " download = " << download->DebugString(true);
731
[email protected]93af2272011-09-21 18:29:17732 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41733 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17734 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21735}
736
[email protected]5656f8a2011-11-17 16:12:58737DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26738 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
739 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26740 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21741 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26742
743 DownloadItem* download = it->second;
744
[email protected]47a881b2011-08-29 22:59:21745 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50746 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01747
[email protected]47a881b2011-08-29 22:59:21748 return download;
749}
[email protected]54610672011-07-18 18:24:43750
[email protected]5656f8a2011-11-17 16:12:58751void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17752 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
753 DCHECK(download);
754
755 // Clean up will happen when the history system create callback runs if we
756 // don't have a valid db_handle yet.
[email protected]5009b7a2012-02-21 18:47:03757 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50758 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17759 delegate_->UpdateItemInPersistentStore(download);
760 }
761}
762
[email protected]fd3a82832012-01-19 20:35:12763bool DownloadManagerImpl::GenerateFileHash() {
764 return delegate_->GenerateFileHash();
765}
766
[email protected]5656f8a2011-11-17 16:12:58767content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
768 return delegate_;
769}
770
771void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17772 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35773 delegate_ = delegate;
774}
775
[email protected]5656f8a2011-11-17 16:12:58776int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04777 const DownloadVector& pending_deletes) {
778 if (pending_deletes.empty())
779 return 0;
780
781 // Delete from internal maps.
782 for (DownloadVector::const_iterator it = pending_deletes.begin();
783 it != pending_deletes.end();
784 ++it) {
785 DownloadItem* download = *it;
786 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50787 history_downloads_.erase(download->GetDbHandle());
788 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04789 downloads_.erase(download);
790 }
791
792 // Tell observers to refresh their views.
793 NotifyModelChanged();
794
795 // Delete the download items themselves.
796 const int num_deleted = static_cast<int>(pending_deletes.size());
797 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
798 return num_deleted;
799}
800
[email protected]fc03de22011-12-06 23:28:12801void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
802 if (history_downloads_.find(download->GetDbHandle()) ==
803 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17804 return;
805
806 // Make history update.
[email protected]93af2272011-09-21 18:29:17807 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29808
809 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04810 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07811 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29812}
813
[email protected]fd3a82832012-01-19 20:35:12814int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
815 base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53816 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29817
[email protected]a312a442010-12-15 23:40:33818 // All downloads visible to the user will be in the history,
819 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04820 DownloadVector pending_deletes;
821 for (DownloadMap::const_iterator it = history_downloads_.begin();
822 it != history_downloads_.end();
823 ++it) {
initial.commit09911bf2008-07-26 23:55:29824 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50825 if (download->GetStartTime() >= remove_begin &&
826 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04827 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12828 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28829 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29830 }
initial.commit09911bf2008-07-26 23:55:29831 }
[email protected]6d0146c2011-08-04 19:13:04832 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29833}
834
[email protected]fd3a82832012-01-19 20:35:12835int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59836 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29837}
838
[email protected]5656f8a2011-11-17 16:12:58839int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06840 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12841 // The null times make the date range unbounded.
842 return RemoveDownloadsBetween(base::Time(), base::Time());
843}
844
[email protected]0d4e30c2012-01-28 00:47:53845void DownloadManagerImpl::DownloadUrl(
[email protected]c5a5c0842012-05-04 20:05:14846 scoped_ptr<content::DownloadUrlParameters> params) {
847 if (params->post_id() >= 0) {
848 // Check this here so that the traceback is more useful.
849 DCHECK(params->prefer_cache());
850 DCHECK(params->method() == "POST");
851 }
852 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
853 &BeginDownload, base::Owned(params.release())));
initial.commit09911bf2008-07-26 23:55:29854}
855
[email protected]5656f8a2011-11-17 16:12:58856void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29857 observers_.AddObserver(observer);
[email protected]a1e41e72012-02-22 17:41:25858 // TODO: It is the responsibility of the observers to query the
859 // DownloadManager. Remove the following call from here and update all
860 // observers.
[email protected]75e51b52012-02-04 16:57:54861 observer->ModelChanged(this);
initial.commit09911bf2008-07-26 23:55:29862}
863
[email protected]5656f8a2011-11-17 16:12:58864void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29865 observers_.RemoveObserver(observer);
866}
867
[email protected]84d57412012-03-03 08:59:55868void DownloadManagerImpl::FileSelected(const FilePath& path,
869 int32 download_id) {
[email protected]4cd82f72011-05-23 19:15:01870 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
871
[email protected]4cd82f72011-05-23 19:15:01872 DownloadItem* download = GetActiveDownloadItem(download_id);
873 if (!download)
874 return;
875 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
876 << " download = " << download->DebugString(true);
877
[email protected]71f55842012-03-24 04:09:02878 // Retain the last directory that was picked by the user. Exclude temporary
879 // downloads since the path likely points at the location of a temporary file.
880 if (download->PromptUserForSaveLocation() && !download->IsTemporary())
[email protected]7ae7c2cb2009-01-06 23:31:41881 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35882
[email protected]4cd82f72011-05-23 19:15:01883 // Make sure the initial file name is set only once.
884 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29885}
886
[email protected]84d57412012-03-03 08:59:55887void DownloadManagerImpl::FileSelectionCanceled(int32 download_id) {
initial.commit09911bf2008-07-26 23:55:29888 // The user didn't pick a place to save the file, so need to cancel the
889 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01890 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01891
892 DownloadItem* download = GetActiveDownloadItem(download_id);
893 if (!download)
894 return;
895
896 VLOG(20) << __FUNCTION__ << "()"
897 << " download = " << download->DebugString(true);
898
[email protected]8f8bc112012-02-22 12:36:31899 download->Cancel(true);
[email protected]4cd82f72011-05-23 19:15:01900}
901
initial.commit09911bf2008-07-26 23:55:29902// Operations posted to us from the history service ----------------------------
903
904// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25905// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58906void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25907 std::vector<DownloadPersistentStoreInfo>* entries) {
initial.commit09911bf2008-07-26 23:55:29908 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]deb40832012-02-23 15:41:37909 int64 db_handle = entries->at(i).db_handle;
910 base::debug::Alias(&db_handle);
[email protected]0634626a2012-05-03 19:04:26911 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]deb40832012-02-23 15:41:37912
[email protected]ef17c9a2012-02-09 05:08:09913 net::BoundNetLog bound_net_log =
914 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12915 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09916 this, GetNextId(), entries->at(i), bound_net_log);
[email protected]f04182f32010-12-10 19:12:07917 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50918 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50919 VLOG(20) << __FUNCTION__ << "()" << i << ">"
920 << " download = " << download->DebugString(true);
initial.commit09911bf2008-07-26 23:55:29921 }
[email protected]b0ab1d42010-02-24 19:29:28922 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48923 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29924}
925
[email protected]5656f8a2011-11-17 16:12:58926void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
927 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27928 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]0634626a2012-05-03 19:04:26929 DCHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33930
[email protected]da4a5582011-10-17 19:08:06931 download_stats::RecordHistorySize(history_downloads_.size());
932
[email protected]5009b7a2012-02-21 18:47:03933 DCHECK(!download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50934 download->SetDbHandle(db_handle);
[email protected]5009b7a2012-02-21 18:47:03935 download->SetIsPersisted();
[email protected]5bcd73eb2011-03-23 21:14:02936
[email protected]0634626a2012-05-03 19:04:26937 DCHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]c09a8fd2011-11-21 19:54:50938 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04939
940 // Show in the appropriate browser UI.
941 // This includes buttons to save or cancel, for a dangerous download.
942 ShowDownloadInBrowser(download);
943
944 // Inform interested objects about the new download.
945 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19946}
947
[email protected]2588ea9d2011-08-22 20:59:53948
[email protected]5656f8a2011-11-17 16:12:58949void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
950 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53951 if (save_page_downloads_.count(download_id)) {
952 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
953 } else if (active_downloads_.count(download_id)) {
954 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
955 }
956 // It's valid that we don't find a matching item, i.e. on shutdown.
957}
958
[email protected]f9a45b02011-06-30 23:49:19959// Once the new DownloadItem's creation info has been committed to the history
960// service, we associate the DownloadItem with the db handle, update our
961// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:58962void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
963 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:19964 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:45965 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:17966 if (!download)
[email protected]19420cc2011-07-18 17:43:45967 return;
[email protected]54610672011-07-18 18:24:43968
969 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
970 << " download_id = " << download_id
971 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:19972
[email protected]e5107ce2011-09-19 20:36:13973 int32 matching_item_download_id
974 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:50975 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:13976 base::debug::Alias(&matching_item_download_id);
977
[email protected]0634626a2012-05-03 19:04:26978 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:20979
[email protected]f9a45b02011-06-30 23:49:19980 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:29981
[email protected]93af2272011-09-21 18:29:17982 // If the download is still in progress, try to complete it.
983 //
984 // Otherwise, download has been cancelled or interrupted before we've
985 // received the DB handle. We post one final message to the history
986 // service so that it can be properly in sync with the DownloadItem's
987 // completion status, and also inform any observers so that they get
988 // more than just the start notification.
989 if (download->IsInProgress()) {
990 MaybeCompleteDownload(download);
991 } else {
[email protected]0634626a2012-05-03 19:04:26992 DCHECK(download->IsCancelled());
[email protected]93af2272011-09-21 18:29:17993 active_downloads_.erase(download_id);
994 delegate_->UpdateItemInPersistentStore(download);
995 download->UpdateObservers();
996 }
initial.commit09911bf2008-07-26 23:55:29997}
998
[email protected]5656f8a2011-11-17 16:12:58999void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]a29e4f22012-04-12 21:22:031000 // The 'contents' may no longer exist if the user closed the contents before
1001 // we get this start completion event.
[email protected]a62d42902012-01-24 17:24:381002 WebContents* content = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:261003
1004 // If the contents no longer exists, we ask the embedder to suggest another
[email protected]a29e4f22012-04-12 21:22:031005 // contents.
[email protected]da1a27b2011-07-29 23:16:331006 if (!content)
[email protected]ef9572e2012-01-04 22:14:121007 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:531008
[email protected]0bfbf882011-12-22 18:19:271009 if (content && content->GetDelegate())
1010 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531011}
1012
[email protected]5656f8a2011-11-17 16:12:581013int DownloadManagerImpl::InProgressCount() const {
[email protected]550520f2012-05-14 20:58:481014 // Don't use active_downloads_.count() because Cancel() leaves items in
1015 // active_downloads_ if they haven't made it into the persistent store yet.
[email protected]007e7412012-03-13 20:10:561016 // Need to actually look at each item's state.
1017 int count = 0;
[email protected]550520f2012-05-14 20:58:481018 for (DownloadMap::const_iterator it = active_downloads_.begin();
1019 it != active_downloads_.end(); ++it) {
[email protected]007e7412012-03-13 20:10:561020 DownloadItem* item = it->second;
1021 if (item->IsInProgress())
1022 ++count;
1023 }
1024 return count;
[email protected]5656f8a2011-11-17 16:12:581025}
1026
[email protected]6cade212008-12-03 00:32:221027// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581028void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411029 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381030}
[email protected]b0ab1d42010-02-24 19:29:281031
[email protected]5656f8a2011-11-17 16:12:581032void DownloadManagerImpl::NotifyModelChanged() {
[email protected]75e51b52012-02-04 16:57:541033 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged(this));
[email protected]b0ab1d42010-02-24 19:29:281034}
1035
[email protected]5656f8a2011-11-17 16:12:581036DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011037 // The |history_downloads_| map is indexed by the download's db_handle,
1038 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071039 for (DownloadMap::iterator it = history_downloads_.begin();
1040 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361041 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501042 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361043 return item;
1044 }
1045 return NULL;
1046}
1047
[email protected]5656f8a2011-11-17 16:12:581048DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361049 if (ContainsKey(active_downloads_, download_id))
1050 return active_downloads_[download_id];
1051 return NULL;
[email protected]4cd82f72011-05-23 19:15:011052}
1053
[email protected]57fd1252010-12-23 17:24:091054// Confirm that everything in all maps is also in |downloads_|, and that
1055// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581056void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071057#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091058 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041059 const DownloadMap* input_maps[] = {&active_downloads_,
1060 &history_downloads_,
1061 &save_page_downloads_};
1062 DownloadSet active_set, history_set, save_page_set;
1063 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1064 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091065 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1066 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041067 it != input_maps[i]->end(); ++it) {
1068 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071069 }
1070 }
[email protected]57fd1252010-12-23 17:24:091071
1072 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091073 DownloadSet downloads_union;
1074 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1075 DownloadSet remainder;
1076 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1077 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1078 downloads_.begin(), downloads_.end(),
1079 insert_it);
1080 DCHECK(remainder.empty());
1081 std::insert_iterator<DownloadSet>
1082 insert_union(downloads_union, downloads_union.end());
1083 std::set_union(downloads_union.begin(), downloads_union.end(),
1084 all_sets[i]->begin(), all_sets[i]->end(),
1085 insert_union);
1086 }
1087
1088 // Is everything in downloads_ present in one of the other sets?
1089 DownloadSet remainder;
1090 std::insert_iterator<DownloadSet>
1091 insert_remainder(remainder, remainder.begin());
1092 std::set_difference(downloads_.begin(), downloads_.end(),
1093 downloads_union.begin(), downloads_union.end(),
1094 insert_remainder);
1095 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071096#endif
1097}
1098
[email protected]6d0146c2011-08-04 19:13:041099// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531100// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041101// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531102// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1103// that the history event is update regardless of the order in which these two
1104// events complete.
[email protected]6d0146c2011-08-04 19:13:041105// If something removes the download item from the download manager (Remove,
1106// Shutdown) the result will be that the SavePage system will not be able to
1107// properly update the download item (which no longer exists) or the download
1108// history, but the action will complete properly anyway. This may lead to the
1109// history entry being wrong on a reload of chrome (specifically in the case of
1110// Initiation -> History Callback -> Removal -> Completion), but there's no way
1111// to solve that without canceling on Remove (which would then update the DB).
1112
[email protected]5656f8a2011-11-17 16:12:581113void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1114 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1116
1117 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1118 // This can happen if the download manager is shutting down and all maps
1119 // have been cleared.
1120 if (it == save_page_downloads_.end())
1121 return;
1122
1123 DownloadItem* download = it->second;
1124 if (!download) {
1125 NOTREACHED();
1126 return;
1127 }
1128
[email protected]0634626a2012-05-03 19:04:261129 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201130
[email protected]6d0146c2011-08-04 19:13:041131 AddDownloadItemToHistory(download, db_handle);
1132
1133 // Finalize this download if it finished before the history callback.
1134 if (!download->IsInProgress())
1135 SavePageDownloadFinished(download);
1136}
1137
[email protected]5656f8a2011-11-17 16:12:581138void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]5009b7a2012-02-21 18:47:031139 if (download->IsPersisted()) {
[email protected]2588ea9d2011-08-22 20:59:531140 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501141 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1142 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041143
1144 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071145 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041146 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531147 content::Source<DownloadManager>(this),
1148 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041149 }
1150}
[email protected]da4a5582011-10-17 19:08:061151
[email protected]fc03de22011-12-06 23:28:121152void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061153 delegate_->UpdateItemInPersistentStore(download);
1154 int num_unopened = 0;
1155 for (DownloadMap::iterator it = history_downloads_.begin();
1156 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501157 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061158 ++num_unopened;
1159 }
1160 download_stats::RecordOpensOutstanding(num_unopened);
1161}
[email protected]5656f8a2011-11-17 16:12:581162
[email protected]5948e1a2012-03-10 00:19:181163void DownloadManagerImpl::SetFileManagerForTesting(
1164 DownloadFileManager* file_manager) {
[email protected]5656f8a2011-11-17 16:12:581165 file_manager_ = file_manager;
1166}