blob: 9bdb48aa7bfbe2382d1e3b34056dbf0f6c79d308 [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]ad50def52011-10-19 23:17:0733#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1634#include "content/public/browser/notification_types.h"
[email protected]f3b1a082011-11-18 00:34:3035#include "content/public/browser/render_process_host.h"
[email protected]0bfbf882011-12-22 18:19:2736#include "content/public/browser/web_contents_delegate.h"
[email protected]27678b2a2012-02-04 22:09:1437#include "net/base/upload_data.h"
initial.commit09911bf2008-07-26 23:55:2938
[email protected]a896ce32012-01-09 22:04:0739// TODO(benjhayden): Change this to DCHECK when we have more debugging
40// information from the next dev cycle, before the next stable/beta branch is
41// cut, in order to prevent unnecessary crashes on those channels. If we still
42// don't have root cause before the dev cycle after the next stable/beta
43// releases, uncomment it out to re-enable debugging checks. Whenever this macro
44// is toggled, the corresponding macro in download_database.cc should also
45// be toggled. When 96627 is fixed, this macro and all its usages can be
46// deleted or permanently changed to DCHECK as appropriate.
47#define CHECK_96627 CHECK
48
[email protected]631bb742011-11-02 11:29:3949using content::BrowserThread;
[email protected]98e814062012-01-27 00:35:4250using content::DownloadId;
[email protected]e582fdd2011-12-20 16:48:1751using content::DownloadItem;
[email protected]8da82ea2012-03-11 22:16:5252using content::DownloadPersistentStoreInfo;
[email protected]ea114722012-03-12 01:11:2553using content::ResourceDispatcherHostImpl;
[email protected]2a6bc3e2011-12-28 23:51:3354using content::WebContents;
[email protected]631bb742011-11-02 11:29:3955
[email protected]a0ce3282011-08-19 20:49:5256namespace {
57
[email protected]fabf36d22011-10-28 21:50:1758// Param structs exist because base::Bind can only handle 6 args.
59struct URLParams {
[email protected]89e6aa72012-03-12 22:51:3360 URLParams(const GURL& url, const GURL& referrer, int64 post_id, bool cache)
61 : url_(url), referrer_(referrer), post_id_(post_id), prefer_cache_(cache) {}
[email protected]fabf36d22011-10-28 21:50:1762 GURL url_;
63 GURL referrer_;
[email protected]27678b2a2012-02-04 22:09:1464 int64 post_id_;
[email protected]89e6aa72012-03-12 22:51:3365 bool prefer_cache_;
[email protected]fabf36d22011-10-28 21:50:1766};
67
68struct RenderParams {
69 RenderParams(int rpi, int rvi)
70 : render_process_id_(rpi), render_view_id_(rvi) {}
71 int render_process_id_;
72 int render_view_id_;
73};
74
[email protected]89e6aa72012-03-12 22:51:3375void BeginDownload(
76 const URLParams& url_params,
[email protected]29a5ffc82012-03-13 19:35:5877 const content::DownloadSaveInfo& save_info,
[email protected]89e6aa72012-03-12 22:51:3378 ResourceDispatcherHostImpl* resource_dispatcher_host,
79 const RenderParams& render_params,
80 content::ResourceContext* context,
81 const content::DownloadManager::OnStartedCallback& callback) {
[email protected]c1ba99842012-01-19 20:56:0582 scoped_ptr<net::URLRequest> request(
83 new net::URLRequest(url_params.url_, resource_dispatcher_host));
[email protected]fabf36d22011-10-28 21:50:1784 request->set_referrer(url_params.referrer_.spec());
[email protected]27678b2a2012-02-04 22:09:1485 if (url_params.post_id_ >= 0) {
86 // The POST in this case does not have an actual body, and only works
87 // when retrieving data from cache. This is done because we don't want
88 // to do a re-POST without user consent, and currently don't have a good
89 // plan on how to display the UI for that.
[email protected]89e6aa72012-03-12 22:51:3390 DCHECK(url_params.prefer_cache_);
[email protected]27678b2a2012-02-04 22:09:1491 request->set_method("POST");
92 scoped_refptr<net::UploadData> upload_data = new net::UploadData();
93 upload_data->set_identifier(url_params.post_id_);
94 request->set_upload(upload_data);
95 }
[email protected]c79a0c02011-08-22 22:37:3796 resource_dispatcher_host->BeginDownload(
[email protected]ea114722012-03-12 01:11:2597 request.Pass(),
98 context,
[email protected]fabf36d22011-10-28 21:50:1799 render_params.render_process_id_,
100 render_params.render_view_id_,
[email protected]89e6aa72012-03-12 22:51:33101 url_params.prefer_cache_,
[email protected]ea114722012-03-12 01:11:25102 save_info,
[email protected]89e6aa72012-03-12 22:51:33103 callback);
[email protected]a0ce3282011-08-19 20:49:52104}
105
[email protected]33d22102012-01-25 17:46:53106class MapValueIteratorAdapter {
107 public:
108 explicit MapValueIteratorAdapter(
109 base::hash_map<int64, DownloadItem*>::const_iterator iter)
110 : iter_(iter) {
111 }
112 ~MapValueIteratorAdapter() {}
113
114 DownloadItem* operator*() { return iter_->second; }
115
116 MapValueIteratorAdapter& operator++() {
117 ++iter_;
118 return *this;
119 }
120
121 bool operator!=(const MapValueIteratorAdapter& that) const {
122 return iter_ != that.iter_;
123 }
124
125 private:
126 base::hash_map<int64, DownloadItem*>::const_iterator iter_;
127 // Allow copy and assign.
128};
129
[email protected]5948e1a2012-03-10 00:19:18130void EnsureNoPendingDownloadsOnFile(scoped_refptr<DownloadFileManager> dfm,
131 bool* result) {
132 if (dfm->NumberOfActiveDownloads())
133 *result = false;
134 BrowserThread::PostTask(
135 BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure());
136}
137
[email protected]0a5c9112012-03-12 17:49:02138void EnsureNoPendingDownloadJobsOnIO(bool* result) {
[email protected]5948e1a2012-03-10 00:19:18139 scoped_refptr<DownloadFileManager> download_file_manager =
[email protected]ea114722012-03-12 01:11:25140 ResourceDispatcherHostImpl::Get()->download_file_manager();
[email protected]5948e1a2012-03-10 00:19:18141 BrowserThread::PostTask(
142 BrowserThread::FILE, FROM_HERE,
143 base::Bind(&EnsureNoPendingDownloadsOnFile,
144 download_file_manager, result));
145}
146
[email protected]a0ce3282011-08-19 20:49:52147} // namespace
148
[email protected]99907362012-01-11 05:41:40149namespace content {
150
151// static
152DownloadManager* DownloadManager::Create(
[email protected]ef17c9a2012-02-09 05:08:09153 content::DownloadManagerDelegate* delegate,
154 net::NetLog* net_log) {
155 return new DownloadManagerImpl(delegate, net_log);
[email protected]99907362012-01-11 05:41:40156}
157
[email protected]5948e1a2012-03-10 00:19:18158bool DownloadManager::EnsureNoPendingDownloadsForTesting() {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 bool result = true;
161 BrowserThread::PostTask(
162 BrowserThread::IO, FROM_HERE,
[email protected]0a5c9112012-03-12 17:49:02163 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result));
[email protected]5948e1a2012-03-10 00:19:18164 MessageLoop::current()->Run();
165 return result;
166}
167
[email protected]99907362012-01-11 05:41:40168} // namespace content
169
[email protected]5656f8a2011-11-17 16:12:58170DownloadManagerImpl::DownloadManagerImpl(
[email protected]ef17c9a2012-02-09 05:08:09171 content::DownloadManagerDelegate* delegate,
172 net::NetLog* net_log)
[email protected]5656f8a2011-11-17 16:12:58173 : shutdown_needed_(false),
174 browser_context_(NULL),
175 file_manager_(NULL),
[email protected]5656f8a2011-11-17 16:12:58176 delegate_(delegate),
[email protected]ef17c9a2012-02-09 05:08:09177 largest_db_handle_in_history_(DownloadItem::kUninitializedHandle),
178 net_log_(net_log) {
initial.commit09911bf2008-07-26 23:55:29179}
180
[email protected]5656f8a2011-11-17 16:12:58181DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13182 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29183}
184
[email protected]5656f8a2011-11-17 16:12:58185DownloadId DownloadManagerImpl::GetNextId() {
[email protected]98e814062012-01-27 00:35:42186 return delegate_->GetNextId();
[email protected]2909e342011-10-29 00:46:53187}
188
[email protected]fc03de22011-12-06 23:28:12189bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
190 return delegate_->ShouldOpenDownload(item);
191}
192
193bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
194 return delegate_->ShouldOpenFileBasedOnExtension(path);
195}
196
[email protected]5656f8a2011-11-17 16:12:58197void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50198 VLOG(20) << __FUNCTION__ << "()"
199 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13200 if (!shutdown_needed_)
201 return;
202 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29203
[email protected]75e51b52012-02-04 16:57:54204 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
[email protected]fb4f8d902011-09-16 06:07:08205 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13206
207 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18208 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17209 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
210 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13211 }
initial.commit09911bf2008-07-26 23:55:29212
[email protected]f04182f32010-12-10 19:12:07213 AssertContainersConsistent();
214
215 // Go through all downloads in downloads_. Dangerous ones we need to
216 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09217 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07218 DownloadItem* download = *it;
219
220 // Save iterator from potential erases in this set done by called code.
221 // Iterators after an erasure point are still valid for lists and
222 // associative containers such as sets.
223 it++;
224
[email protected]c09a8fd2011-11-21 19:54:50225 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29226 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07227 // The user hasn't accepted it, so we need to remove it
228 // from the disk. This may or may not result in it being
229 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12230 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07231 // removes and deletes it if it's known to the history service)
232 // so the only thing we know after calling this function is that
233 // the download was deleted if-and-only-if it was removed
234 // from all queues.
[email protected]303077002011-04-19 23:21:01235 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26236 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17237 download->Cancel(false);
238 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29239 }
240 }
241
[email protected]f04182f32010-12-10 19:12:07242 // At this point, all dangerous downloads have had their files removed
243 // and all in progress downloads have been cancelled. We can now delete
244 // anything left.
[email protected]9ccbb372008-10-10 18:50:32245
[email protected]5cd11b6e2011-06-10 20:30:59246 // Copy downloads_ to separate container so as not to set off checks
247 // in DownloadItem destruction.
248 DownloadSet downloads_to_delete;
249 downloads_to_delete.swap(downloads_);
250
initial.commit09911bf2008-07-26 23:55:29251 in_progress_.clear();
[email protected]70850c72011-01-11 17:31:27252 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59253 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59254 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29255
[email protected]41f558fb2012-01-09 22:59:58256 // We'll have nothing more to report to the observers after this point.
257 observers_.Clear();
258
[email protected]6d0146c2011-08-04 19:13:04259 DCHECK(save_page_downloads_.empty());
260
initial.commit09911bf2008-07-26 23:55:29261 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53262 delegate_->Shutdown();
initial.commit09911bf2008-07-26 23:55:29263}
264
[email protected]5656f8a2011-11-17 16:12:58265void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04266 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57267 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58268
[email protected]f04182f32010-12-10 19:12:07269 for (DownloadMap::iterator it = history_downloads_.begin();
270 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50271 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20272 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57273 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58274 }
[email protected]6aa4a1c02010-01-15 18:49:58275}
276
[email protected]5656f8a2011-11-17 16:12:58277void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04278 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57279 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34280
[email protected]f04182f32010-12-10 19:12:07281 for (DownloadMap::iterator it = history_downloads_.begin();
282 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50283 if (!it->second->IsTemporary() &&
284 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57285 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34286 }
[email protected]8ddbd66a2010-05-21 16:38:34287}
288
[email protected]5656f8a2011-11-17 16:12:58289void DownloadManagerImpl::SearchDownloads(const string16& query,
290 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26291 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42292
[email protected]f04182f32010-12-10 19:12:07293 for (DownloadMap::iterator it = history_downloads_.begin();
294 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42295 DownloadItem* download_item = it->second;
296
[email protected]c09a8fd2011-11-21 19:54:50297 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42298 continue;
299
300 // Display Incognito downloads only in Incognito window, and vice versa.
301 // The Incognito Downloads page will get the list of non-Incognito downloads
302 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50303 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42304 continue;
305
306 if (download_item->MatchesQuery(query_lower))
307 result->push_back(download_item);
308 }
[email protected]d3b12902010-08-16 23:39:42309}
310
initial.commit09911bf2008-07-26 23:55:29311// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58312bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03313 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29314 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
315 shutdown_needed_ = true;
316
[email protected]6d0c9fb2011-08-22 19:26:03317 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46318
[email protected]ea114722012-03-12 01:11:25319 // In test mode, there may be no ResourceDispatcherHostImpl. In this case
320 // it's safe to avoid setting |file_manager_| because we only call a small
321 // set of functions, none of which need it.
322 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
[email protected]b39e7a88b2012-01-10 21:43:17323 if (rdh) {
324 file_manager_ = rdh->download_file_manager();
325 DCHECK(file_manager_);
326 }
initial.commit09911bf2008-07-26 23:55:29327
initial.commit09911bf2008-07-26 23:55:29328 return true;
329}
330
[email protected]aa9881c2011-08-15 18:01:12331// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58332void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35334
[email protected]aa9881c2011-08-15 18:01:12335 if (delegate_->ShouldStartDownload(download_id))
336 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35337}
338
[email protected]5656f8a2011-11-17 16:12:58339void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341 for (DownloadMap::iterator it = history_downloads_.begin();
342 it != history_downloads_.end(); ++it) {
343 CheckForFileRemoval(it->second);
344 }
345}
346
[email protected]5656f8a2011-11-17 16:12:58347void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
349 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50350 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48351 BrowserThread::PostTask(
352 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58353 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50354 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17355 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48356 }
357}
358
[email protected]5656f8a2011-11-17 16:12:58359void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48360 int64 db_handle, const FilePath& path) {
361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
362 if (!file_util::PathExists(path)) {
363 BrowserThread::PostTask(
364 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58365 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
366 this,
367 db_handle));
[email protected]9fc114672011-06-15 08:17:48368 }
369}
370
[email protected]5656f8a2011-11-17 16:12:58371void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
373 DownloadMap::iterator it = history_downloads_.find(db_handle);
374 if (it != history_downloads_.end()) {
375 DownloadItem* download_item = it->second;
376 download_item->OnDownloadedFileRemoved();
377 }
378}
379
[email protected]443853c62011-12-22 19:22:41380void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29382
[email protected]4cd82f72011-05-23 19:15:01383 DownloadItem* download = GetActiveDownloadItem(download_id);
384 if (!download)
385 return;
386
387 VLOG(20) << __FUNCTION__ << "()"
388 << " download = " << download->DebugString(true);
389
[email protected]c09a8fd2011-11-21 19:54:50390 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01391
[email protected]c09a8fd2011-11-21 19:54:50392 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29393 // We must ask the user for the place to put the download.
[email protected]a62d42902012-01-24 17:24:38394 WebContents* contents = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:26395
[email protected]795b76a2011-12-14 16:52:53396 FilePath target_path;
397 // If |download| is a potentially dangerous file, then |suggested_path|
398 // contains the intermediate name instead of the final download
399 // filename. The latter is GetTargetName().
[email protected]a62d42902012-01-24 17:24:38400 if (download->GetDangerType() !=
401 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
[email protected]795b76a2011-12-14 16:52:53402 target_path = suggested_path.DirName().Append(download->GetTargetName());
403 else
404 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26405
[email protected]795b76a2011-12-14 16:52:53406 delegate_->ChooseDownloadPath(contents, target_path,
[email protected]84d57412012-03-03 08:59:55407 download_id);
[email protected]f5920322011-03-24 20:34:16408 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]75e51b52012-02-04 16:57:54409 SelectFileDialogDisplayed(this, download_id));
initial.commit09911bf2008-07-26 23:55:29410 } else {
411 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01412 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29413 }
414}
415
[email protected]37757c62011-12-20 20:07:12416content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58417 return browser_context_;
418}
419
420FilePath DownloadManagerImpl::LastDownloadPath() {
421 return last_download_path_;
422}
423
[email protected]ef17c9a2012-02-09 05:08:09424net::BoundNetLog DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41425 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
427
[email protected]ef17c9a2012-02-09 05:08:09428 net::BoundNetLog bound_net_log =
429 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]c09a8fd2011-11-21 19:54:50430 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29431 this, *info, new DownloadRequestHandle(request_handle),
[email protected]ef17c9a2012-02-09 05:08:09432 browser_context_->IsOffTheRecord(), bound_net_log);
[email protected]2909e342011-10-29 00:46:53433 int32 download_id = info->download_id.local();
[email protected]4cd82f72011-05-23 19:15:01434 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]d8472d92011-08-26 20:15:20435
[email protected]a896ce32012-01-09 22:04:07436 CHECK_96627(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29437 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01438 active_downloads_[download_id] = download;
[email protected]ef17c9a2012-02-09 05:08:09439
440 return bound_net_log;
[email protected]c2e76012010-12-23 21:10:29441}
442
[email protected]fc03de22011-12-06 23:28:12443DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
444 const FilePath& main_file_path,
445 const GURL& page_url,
446 bool is_otr,
447 DownloadItem::Observer* observer) {
[email protected]ef17c9a2012-02-09 05:08:09448 net::BoundNetLog bound_net_log =
449 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12450 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09451 this, main_file_path, page_url, is_otr, GetNextId(), bound_net_log);
[email protected]fc03de22011-12-06 23:28:12452
453 download->AddObserver(observer);
454
455 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
456 downloads_.insert(download);
457 save_page_downloads_[download->GetId()] = download;
458
459 // Will notify the observer in the callback.
460 delegate_->AddItemToPersistentStore(download);
461
462 return download;
463}
464
[email protected]795b76a2011-12-14 16:52:53465// For non-safe downloads with no prompting, |chosen_file| is the intermediate
466// path for saving the in-progress download. The final target filename for these
467// is |download->GetTargetName()|. For all other downloads (non-safe downloads
468// for which we have prompted for a save location, and all safe downloads),
469// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58470void DownloadManagerImpl::ContinueDownloadWithPath(
471 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01473 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39474
[email protected]c09a8fd2011-11-21 19:54:50475 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29476
[email protected]70850c72011-01-11 17:31:27477 // NOTE(ahendrickson) Eventually |active_downloads_| will replace
478 // |in_progress_|, but we don't want to change the semantics yet.
[email protected]4cd82f72011-05-23 19:15:01479 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]70850c72011-01-11 17:31:27480 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01481 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27482
[email protected]4cd82f72011-05-23 19:15:01483 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20484 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01485 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01486
487 VLOG(20) << __FUNCTION__ << "()"
488 << " download = " << download->DebugString(true);
489
490 in_progress_[download_id] = download;
initial.commit09911bf2008-07-26 23:55:29491
[email protected]adb2f3d12011-01-23 16:24:54492 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16493 FilePath download_path;
[email protected]385e93182012-01-30 17:11:03494 if (download->GetDangerType() !=
495 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
496 if (download->PromptUserForSaveLocation()) {
497 // When we prompt the user, we overwrite the FullPath with what the user
498 // wanted to use. Construct a file path using the previously determined
499 // intermediate filename and the new path.
500 // TODO(asanka): This can trample an in-progress download in the new
501 // target directory if it was using the same intermediate name.
502 FilePath file_name = download->GetSuggestedPath().BaseName();
503 download_path = download->GetFullPath().DirName().Append(file_name);
504 } else {
505 // The download's name is already set to an intermediate name, so no need
506 // to override.
507 download_path = download->GetFullPath();
508 }
509 } else {
510 // The download is a safe download. We need to rename it to its
511 // intermediate path. The final name after user confirmation will be set
512 // from DownloadItem::OnDownloadCompleting.
513 download_path = delegate_->GetIntermediatePath(download->GetFullPath());
514 }
[email protected]594cd7d2010-07-21 03:23:56515
[email protected]f5920322011-03-24 20:34:16516 BrowserThread::PostTask(
517 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17518 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12519 file_manager_, download->GetGlobalId(),
520 download_path));
[email protected]f5920322011-03-24 20:34:16521
522 download->Rename(download_path);
523
[email protected]2588ea9d2011-08-22 20:59:53524 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29525}
526
[email protected]443853c62011-12-22 19:22:41527void DownloadManagerImpl::UpdateDownload(int32 download_id,
528 int64 bytes_so_far,
529 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00530 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27531 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
532 DownloadMap::iterator it = active_downloads_.find(download_id);
533 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29534 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26535 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41536 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]2588ea9d2011-08-22 20:59:53537 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27538 }
initial.commit09911bf2008-07-26 23:55:29539 }
540}
541
[email protected]5656f8a2011-11-17 16:12:58542void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
543 int64 size,
544 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50546 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
547 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32549
[email protected]c4f02c42011-01-24 21:55:06550 // If it's not in active_downloads_, that means it was cancelled; just
551 // ignore the notification.
552 if (active_downloads_.count(download_id) == 0)
553 return;
554
[email protected]adb2f3d12011-01-23 16:24:54555 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37556 download->OnAllDataSaved(size, hash);
[email protected]b09f1282011-09-14 00:37:45557
[email protected]fc03de22011-12-06 23:28:12558 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54559}
[email protected]9ccbb372008-10-10 18:50:32560
[email protected]fc03de22011-12-06 23:28:12561void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]a896ce32012-01-09 22:04:07562 // TODO(rdsmith): Change to DCHECK after http://crbug.com/96627 resolved.
[email protected]c09a8fd2011-11-21 19:54:50563 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]7d413112011-06-16 18:50:17564 CHECK(!ContainsKey(downloads_, download));
[email protected]c09a8fd2011-11-21 19:54:50565 CHECK(!ContainsKey(active_downloads_, download->GetId()));
566 CHECK(!ContainsKey(in_progress_, download->GetId()));
567 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17568 return;
569 }
570
571 // Should be in downloads_ if we're not REMOVING.
572 CHECK(ContainsKey(downloads_, download));
573
574 // Check history_downloads_ consistency.
[email protected]5009b7a2012-02-21 18:47:03575 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50576 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17577 } else {
[email protected]fc03de22011-12-06 23:28:12578 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17579 it != history_downloads_.end(); ++it) {
[email protected]a896ce32012-01-09 22:04:07580 CHECK_96627(it->second != download);
[email protected]7d413112011-06-16 18:50:17581 }
582 }
583
[email protected]c09a8fd2011-11-21 19:54:50584 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34585 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50586 if (ContainsKey(active_downloads_, download->GetId())) {
[email protected]5009b7a2012-02-21 18:47:03587 if (download->IsPersisted())
[email protected]c09a8fd2011-11-21 19:54:50588 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
589 if (DownloadItem::IN_PROGRESS != download->GetState())
590 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07591 }
[email protected]c09a8fd2011-11-21 19:54:50592 if (DownloadItem::IN_PROGRESS == download->GetState())
593 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59594}
595
[email protected]5656f8a2011-11-17 16:12:58596bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54597 // If we don't have all the data, the download is not ready for
598 // completion.
[email protected]c09a8fd2011-11-21 19:54:50599 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54600 return false;
[email protected]6a7fb042010-02-01 16:30:47601
[email protected]9d7ef802011-02-25 19:03:35602 // If the download is dangerous, but not yet validated, it's not ready for
603 // completion.
[email protected]c09a8fd2011-11-21 19:54:50604 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35605 return false;
606
[email protected]adb2f3d12011-01-23 16:24:54607 // If the download isn't active (e.g. has been cancelled) it's not
608 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50609 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54610 return false;
611
612 // If the download hasn't been inserted into the history system
613 // (which occurs strictly after file name determination, intermediate
614 // file rename, and UI display) then it's not ready for completion.
[email protected]5009b7a2012-02-21 18:47:03615 if (!download->IsPersisted())
[email protected]7054b592011-06-22 14:46:42616 return false;
617
618 return true;
[email protected]adb2f3d12011-01-23 16:24:54619}
620
[email protected]5656f8a2011-11-17 16:12:58621void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54622 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
623 VLOG(20) << __FUNCTION__ << "()" << " download = "
624 << download->DebugString(false);
625
626 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32627 return;
[email protected]9ccbb372008-10-10 18:50:32628
[email protected]adb2f3d12011-01-23 16:24:54629 // TODO(rdsmith): DCHECK that we only pass through this point
630 // once per download. The natural way to do this is by a state
631 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56632
[email protected]adb2f3d12011-01-23 16:24:54633 // Confirm we're in the proper set of states to be here;
[email protected]9d7ef802011-02-25 19:03:35634 // in in_progress_, have all data, have a history handle, (validated or safe).
[email protected]c09a8fd2011-11-21 19:54:50635 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
636 DCHECK_EQ(1u, in_progress_.count(download->GetId()));
637 DCHECK(download->AllDataSaved());
[email protected]5009b7a2012-02-21 18:47:03638 DCHECK(download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50639 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54640
[email protected]c2918652011-11-01 18:50:23641 // Give the delegate a chance to override.
642 if (!delegate_->ShouldCompleteDownload(download))
643 return;
644
[email protected]adb2f3d12011-01-23 16:24:54645 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
646 << download->DebugString(false);
647
648 // Remove the id from in_progress
[email protected]c09a8fd2011-11-21 19:54:50649 in_progress_.erase(download->GetId());
[email protected]adb2f3d12011-01-23 16:24:54650
[email protected]2588ea9d2011-08-22 20:59:53651 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54652
[email protected]f5920322011-03-24 20:34:16653 // Finish the download.
[email protected]48837962011-04-19 17:03:29654 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32655}
656
[email protected]fc03de22011-12-06 23:28:12657void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27658 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21659 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53660 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12661 active_downloads_.erase(download->GetId());
662 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27663}
664
[email protected]5656f8a2011-11-17 16:12:58665void DownloadManagerImpl::OnDownloadRenamedToFinalName(
666 int download_id,
667 const FilePath& full_path,
668 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50669 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16670 << " full_path = \"" << full_path.value() << "\""
671 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18672 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16673
[email protected]2e030682010-07-23 19:45:36674 DownloadItem* item = GetDownloadItem(download_id);
675 if (!item)
676 return;
[email protected]6cade212008-12-03 00:32:22677
[email protected]a62d42902012-01-24 17:24:38678 if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
[email protected]795b76a2011-12-14 16:52:53679 item->PromptUserForSaveLocation()) {
680 DCHECK_EQ(0, uniquifier)
681 << "We should not uniquify user supplied filenames or safe filenames "
682 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02683 }
684
[email protected]fabf36d22011-10-28 21:50:17685 BrowserThread::PostTask(
686 BrowserThread::FILE, FROM_HERE,
687 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50688 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32689
[email protected]f5920322011-03-24 20:34:16690 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50691 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32692
[email protected]f5920322011-03-24 20:34:16693 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53694 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29695}
696
[email protected]5656f8a2011-11-17 16:12:58697void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17698 DownloadItem* download = GetActiveDownload(download_id);
699 // A cancel at the right time could remove the download from the
700 // |active_downloads_| map before we get here.
701 if (!download)
702 return;
703
704 download->Cancel(true);
705}
706
[email protected]fc03de22011-12-06 23:28:12707void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20708 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20709
710 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50711 << " download = " << download->DebugString(true);
712
[email protected]93af2272011-09-21 18:29:17713 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21714 // This function is called from the DownloadItem, so DI state
715 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12716 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29717
[email protected]15d90ba2011-11-03 03:41:55718 if (file_manager_)
719 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29720}
721
[email protected]bf3b08a2012-03-08 01:52:34722void DownloadManagerImpl::OnDownloadInterrupted(
723 int32 download_id,
724 int64 size,
725 const std::string& hash_state,
726 content::DownloadInterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
728
729 DownloadItem* download = GetActiveDownload(download_id);
730 if (!download)
731 return;
732
[email protected]be76b7e2011-10-13 12:57:57733 VLOG(20) << __FUNCTION__ << "()"
734 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50735 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21736 << " size = " << size
737 << " download = " << download->DebugString(true);
738
[email protected]93af2272011-09-21 18:29:17739 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41740 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17741 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21742}
743
[email protected]5656f8a2011-11-17 16:12:58744DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26745 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
746 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26747 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21748 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26749
750 DownloadItem* download = it->second;
751
[email protected]47a881b2011-08-29 22:59:21752 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50753 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01754
[email protected]47a881b2011-08-29 22:59:21755 return download;
756}
[email protected]54610672011-07-18 18:24:43757
[email protected]5656f8a2011-11-17 16:12:58758void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17759 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
760 DCHECK(download);
761
762 // Clean up will happen when the history system create callback runs if we
763 // don't have a valid db_handle yet.
[email protected]5009b7a2012-02-21 18:47:03764 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50765 in_progress_.erase(download->GetId());
766 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17767 delegate_->UpdateItemInPersistentStore(download);
768 }
769}
770
[email protected]fd3a82832012-01-19 20:35:12771bool DownloadManagerImpl::GenerateFileHash() {
772 return delegate_->GenerateFileHash();
773}
774
[email protected]5656f8a2011-11-17 16:12:58775content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
776 return delegate_;
777}
778
779void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17780 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35781 delegate_ = delegate;
782}
783
[email protected]5656f8a2011-11-17 16:12:58784int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04785 const DownloadVector& pending_deletes) {
786 if (pending_deletes.empty())
787 return 0;
788
789 // Delete from internal maps.
790 for (DownloadVector::const_iterator it = pending_deletes.begin();
791 it != pending_deletes.end();
792 ++it) {
793 DownloadItem* download = *it;
794 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50795 history_downloads_.erase(download->GetDbHandle());
796 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04797 downloads_.erase(download);
798 }
799
800 // Tell observers to refresh their views.
801 NotifyModelChanged();
802
803 // Delete the download items themselves.
804 const int num_deleted = static_cast<int>(pending_deletes.size());
805 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
806 return num_deleted;
807}
808
[email protected]fc03de22011-12-06 23:28:12809void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
810 if (history_downloads_.find(download->GetDbHandle()) ==
811 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17812 return;
813
814 // Make history update.
[email protected]93af2272011-09-21 18:29:17815 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29816
817 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04818 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07819 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29820}
821
[email protected]fd3a82832012-01-19 20:35:12822int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
823 base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53824 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29825
[email protected]a312a442010-12-15 23:40:33826 // All downloads visible to the user will be in the history,
827 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04828 DownloadVector pending_deletes;
829 for (DownloadMap::const_iterator it = history_downloads_.begin();
830 it != history_downloads_.end();
831 ++it) {
initial.commit09911bf2008-07-26 23:55:29832 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50833 if (download->GetStartTime() >= remove_begin &&
834 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04835 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12836 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28837 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29838 }
initial.commit09911bf2008-07-26 23:55:29839 }
[email protected]6d0146c2011-08-04 19:13:04840 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29841}
842
[email protected]fd3a82832012-01-19 20:35:12843int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59844 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29845}
846
[email protected]5656f8a2011-11-17 16:12:58847int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06848 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12849 // The null times make the date range unbounded.
850 return RemoveDownloadsBetween(base::Time(), base::Time());
851}
852
initial.commit09911bf2008-07-26 23:55:29853// Initiate a download of a specific URL. We send the request to the
854// ResourceDispatcherHost, and let it send us responses like a regular
855// download.
[email protected]0d4e30c2012-01-28 00:47:53856void DownloadManagerImpl::DownloadUrl(
857 const GURL& url,
858 const GURL& referrer,
859 const std::string& referrer_charset,
860 bool prefer_cache,
[email protected]27678b2a2012-02-04 22:09:14861 int64 post_id,
[email protected]29a5ffc82012-03-13 19:35:58862 const content::DownloadSaveInfo& save_info,
[email protected]89e6aa72012-03-12 22:51:33863 WebContents* web_contents,
864 const OnStartedCallback& callback) {
[email protected]ea114722012-03-12 01:11:25865 ResourceDispatcherHostImpl* resource_dispatcher_host =
866 ResourceDispatcherHostImpl::Get();
867 DCHECK(resource_dispatcher_host);
[email protected]443853c62011-12-22 19:22:41868
[email protected]ed24fad2011-05-10 22:44:01869 // We send a pointer to content::ResourceContext, instead of the usual
870 // reference, so that a copy of the object isn't made.
[email protected]fabf36d22011-10-28 21:50:17871 // base::Bind can't handle 7 args, so we use URLParams and RenderParams.
872 BrowserThread::PostTask(
873 BrowserThread::IO, FROM_HERE,
[email protected]0d4e30c2012-01-28 00:47:53874 base::Bind(
875 &BeginDownload,
[email protected]89e6aa72012-03-12 22:51:33876 URLParams(url, referrer, post_id, prefer_cache),
[email protected]0d4e30c2012-01-28 00:47:53877 save_info,
878 resource_dispatcher_host,
[email protected]fbc5e5f92012-01-02 06:08:32879 RenderParams(web_contents->GetRenderProcessHost()->GetID(),
[email protected]9f76c1e2012-03-05 15:15:58880 web_contents->GetRenderViewHost()->GetRoutingID()),
[email protected]89e6aa72012-03-12 22:51:33881 web_contents->GetBrowserContext()->GetResourceContext(),
882 callback));
initial.commit09911bf2008-07-26 23:55:29883}
884
[email protected]5656f8a2011-11-17 16:12:58885void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29886 observers_.AddObserver(observer);
[email protected]a1e41e72012-02-22 17:41:25887 // TODO: It is the responsibility of the observers to query the
888 // DownloadManager. Remove the following call from here and update all
889 // observers.
[email protected]75e51b52012-02-04 16:57:54890 observer->ModelChanged(this);
initial.commit09911bf2008-07-26 23:55:29891}
892
[email protected]5656f8a2011-11-17 16:12:58893void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29894 observers_.RemoveObserver(observer);
895}
896
[email protected]84d57412012-03-03 08:59:55897void DownloadManagerImpl::FileSelected(const FilePath& path,
898 int32 download_id) {
[email protected]4cd82f72011-05-23 19:15:01899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
900
[email protected]4cd82f72011-05-23 19:15:01901 DownloadItem* download = GetActiveDownloadItem(download_id);
902 if (!download)
903 return;
904 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
905 << " download = " << download->DebugString(true);
906
[email protected]71f55842012-03-24 04:09:02907 // Retain the last directory that was picked by the user. Exclude temporary
908 // downloads since the path likely points at the location of a temporary file.
909 if (download->PromptUserForSaveLocation() && !download->IsTemporary())
[email protected]7ae7c2cb2009-01-06 23:31:41910 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35911
[email protected]4cd82f72011-05-23 19:15:01912 // Make sure the initial file name is set only once.
913 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29914}
915
[email protected]84d57412012-03-03 08:59:55916void DownloadManagerImpl::FileSelectionCanceled(int32 download_id) {
initial.commit09911bf2008-07-26 23:55:29917 // The user didn't pick a place to save the file, so need to cancel the
918 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01919 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01920
921 DownloadItem* download = GetActiveDownloadItem(download_id);
922 if (!download)
923 return;
924
925 VLOG(20) << __FUNCTION__ << "()"
926 << " download = " << download->DebugString(true);
927
[email protected]8f8bc112012-02-22 12:36:31928 download->Cancel(true);
[email protected]4cd82f72011-05-23 19:15:01929}
930
initial.commit09911bf2008-07-26 23:55:29931// Operations posted to us from the history service ----------------------------
932
933// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25934// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58935void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25936 std::vector<DownloadPersistentStoreInfo>* entries) {
[email protected]d8472d92011-08-26 20:15:20937 // TODO(rdsmith): Remove this and related logic when
[email protected]a896ce32012-01-09 22:04:07938 // http://crbug.com/96627 is fixed.
[email protected]d8472d92011-08-26 20:15:20939 largest_db_handle_in_history_ = 0;
940
initial.commit09911bf2008-07-26 23:55:29941 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]deb40832012-02-23 15:41:37942 int64 db_handle = entries->at(i).db_handle;
943 base::debug::Alias(&db_handle);
944 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
945
[email protected]ef17c9a2012-02-09 05:08:09946 net::BoundNetLog bound_net_log =
947 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12948 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09949 this, GetNextId(), entries->at(i), bound_net_log);
[email protected]f04182f32010-12-10 19:12:07950 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50951 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50952 VLOG(20) << __FUNCTION__ << "()" << i << ">"
953 << " download = " << download->DebugString(true);
[email protected]d8472d92011-08-26 20:15:20954
[email protected]c09a8fd2011-11-21 19:54:50955 if (download->GetDbHandle() > largest_db_handle_in_history_)
956 largest_db_handle_in_history_ = download->GetDbHandle();
initial.commit09911bf2008-07-26 23:55:29957 }
[email protected]b0ab1d42010-02-24 19:29:28958 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48959 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29960}
961
[email protected]5656f8a2011-11-17 16:12:58962void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
963 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27964 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d2a8fb72010-01-21 05:31:42965
[email protected]a896ce32012-01-09 22:04:07966 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]1e9fe7ff2011-06-24 17:37:33967 // is fixed.
[email protected]2588ea9d2011-08-22 20:59:53968 CHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33969
[email protected]da4a5582011-10-17 19:08:06970 download_stats::RecordHistorySize(history_downloads_.size());
971
[email protected]5009b7a2012-02-21 18:47:03972 DCHECK(!download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50973 download->SetDbHandle(db_handle);
[email protected]5009b7a2012-02-21 18:47:03974 download->SetIsPersisted();
[email protected]5bcd73eb2011-03-23 21:14:02975
[email protected]a896ce32012-01-09 22:04:07976 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]d8472d92011-08-26 20:15:20977 // is fixed.
[email protected]a896ce32012-01-09 22:04:07978 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]c09a8fd2011-11-21 19:54:50979 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04980
981 // Show in the appropriate browser UI.
982 // This includes buttons to save or cancel, for a dangerous download.
983 ShowDownloadInBrowser(download);
984
985 // Inform interested objects about the new download.
986 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19987}
988
[email protected]2588ea9d2011-08-22 20:59:53989
[email protected]5656f8a2011-11-17 16:12:58990void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
991 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53992 if (save_page_downloads_.count(download_id)) {
993 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
994 } else if (active_downloads_.count(download_id)) {
995 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
996 }
997 // It's valid that we don't find a matching item, i.e. on shutdown.
998}
999
[email protected]f9a45b02011-06-30 23:49:191000// Once the new DownloadItem's creation info has been committed to the history
1001// service, we associate the DownloadItem with the db handle, update our
1002// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:581003void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
1004 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:191005 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:451006 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:171007 if (!download)
[email protected]19420cc2011-07-18 17:43:451008 return;
[email protected]54610672011-07-18 18:24:431009
1010 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
1011 << " download_id = " << download_id
1012 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:191013
[email protected]a896ce32012-01-09 22:04:071014 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201015 int64 largest_handle = largest_db_handle_in_history_;
1016 base::debug::Alias(&largest_handle);
[email protected]e5107ce2011-09-19 20:36:131017 int32 matching_item_download_id
1018 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:501019 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:131020 base::debug::Alias(&matching_item_download_id);
1021
[email protected]a896ce32012-01-09 22:04:071022 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201023
[email protected]f9a45b02011-06-30 23:49:191024 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:291025
[email protected]93af2272011-09-21 18:29:171026 // If the download is still in progress, try to complete it.
1027 //
1028 // Otherwise, download has been cancelled or interrupted before we've
1029 // received the DB handle. We post one final message to the history
1030 // service so that it can be properly in sync with the DownloadItem's
1031 // completion status, and also inform any observers so that they get
1032 // more than just the start notification.
1033 if (download->IsInProgress()) {
1034 MaybeCompleteDownload(download);
1035 } else {
[email protected]a896ce32012-01-09 22:04:071036 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]93af2272011-09-21 18:29:171037 // is fixed.
1038 CHECK(download->IsCancelled())
1039 << " download = " << download->DebugString(true);
1040 in_progress_.erase(download_id);
1041 active_downloads_.erase(download_id);
1042 delegate_->UpdateItemInPersistentStore(download);
1043 download->UpdateObservers();
1044 }
initial.commit09911bf2008-07-26 23:55:291045}
1046
[email protected]5656f8a2011-11-17 16:12:581047void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]a29e4f22012-04-12 21:22:031048 // The 'contents' may no longer exist if the user closed the contents before
1049 // we get this start completion event.
[email protected]a62d42902012-01-24 17:24:381050 WebContents* content = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:261051
1052 // If the contents no longer exists, we ask the embedder to suggest another
[email protected]a29e4f22012-04-12 21:22:031053 // contents.
[email protected]da1a27b2011-07-29 23:16:331054 if (!content)
[email protected]ef9572e2012-01-04 22:14:121055 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:531056
[email protected]0bfbf882011-12-22 18:19:271057 if (content && content->GetDelegate())
1058 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531059}
1060
[email protected]5656f8a2011-11-17 16:12:581061int DownloadManagerImpl::InProgressCount() const {
[email protected]007e7412012-03-13 20:10:561062 // Don't use in_progress_.count() because Cancel() leaves items in
1063 // in_progress_ if they haven't made it into the persistent store yet.
1064 // Need to actually look at each item's state.
1065 int count = 0;
1066 for (DownloadMap::const_iterator it = in_progress_.begin();
1067 it != in_progress_.end(); ++it) {
1068 DownloadItem* item = it->second;
1069 if (item->IsInProgress())
1070 ++count;
1071 }
1072 return count;
[email protected]5656f8a2011-11-17 16:12:581073}
1074
[email protected]6cade212008-12-03 00:32:221075// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581076void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411077 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381078}
[email protected]b0ab1d42010-02-24 19:29:281079
[email protected]5656f8a2011-11-17 16:12:581080void DownloadManagerImpl::NotifyModelChanged() {
[email protected]75e51b52012-02-04 16:57:541081 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged(this));
[email protected]b0ab1d42010-02-24 19:29:281082}
1083
[email protected]5656f8a2011-11-17 16:12:581084DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011085 // The |history_downloads_| map is indexed by the download's db_handle,
1086 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071087 for (DownloadMap::iterator it = history_downloads_.begin();
1088 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361089 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501090 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361091 return item;
1092 }
1093 return NULL;
1094}
1095
[email protected]5656f8a2011-11-17 16:12:581096DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361097 if (ContainsKey(active_downloads_, download_id))
1098 return active_downloads_[download_id];
1099 return NULL;
[email protected]4cd82f72011-05-23 19:15:011100}
1101
[email protected]57fd1252010-12-23 17:24:091102// Confirm that everything in all maps is also in |downloads_|, and that
1103// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581104void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071105#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091106 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041107 const DownloadMap* input_maps[] = {&active_downloads_,
1108 &history_downloads_,
1109 &save_page_downloads_};
1110 DownloadSet active_set, history_set, save_page_set;
1111 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1112 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091113 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1114 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041115 it != input_maps[i]->end(); ++it) {
1116 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071117 }
1118 }
[email protected]57fd1252010-12-23 17:24:091119
1120 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091121 DownloadSet downloads_union;
1122 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1123 DownloadSet remainder;
1124 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1125 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1126 downloads_.begin(), downloads_.end(),
1127 insert_it);
1128 DCHECK(remainder.empty());
1129 std::insert_iterator<DownloadSet>
1130 insert_union(downloads_union, downloads_union.end());
1131 std::set_union(downloads_union.begin(), downloads_union.end(),
1132 all_sets[i]->begin(), all_sets[i]->end(),
1133 insert_union);
1134 }
1135
1136 // Is everything in downloads_ present in one of the other sets?
1137 DownloadSet remainder;
1138 std::insert_iterator<DownloadSet>
1139 insert_remainder(remainder, remainder.begin());
1140 std::set_difference(downloads_.begin(), downloads_.end(),
1141 downloads_union.begin(), downloads_union.end(),
1142 insert_remainder);
1143 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071144#endif
1145}
1146
[email protected]6d0146c2011-08-04 19:13:041147// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531148// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041149// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531150// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1151// that the history event is update regardless of the order in which these two
1152// events complete.
[email protected]6d0146c2011-08-04 19:13:041153// If something removes the download item from the download manager (Remove,
1154// Shutdown) the result will be that the SavePage system will not be able to
1155// properly update the download item (which no longer exists) or the download
1156// history, but the action will complete properly anyway. This may lead to the
1157// history entry being wrong on a reload of chrome (specifically in the case of
1158// Initiation -> History Callback -> Removal -> Completion), but there's no way
1159// to solve that without canceling on Remove (which would then update the DB).
1160
[email protected]5656f8a2011-11-17 16:12:581161void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1162 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1164
1165 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1166 // This can happen if the download manager is shutting down and all maps
1167 // have been cleared.
1168 if (it == save_page_downloads_.end())
1169 return;
1170
1171 DownloadItem* download = it->second;
1172 if (!download) {
1173 NOTREACHED();
1174 return;
1175 }
1176
[email protected]a896ce32012-01-09 22:04:071177 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201178 int64 largest_handle = largest_db_handle_in_history_;
1179 base::debug::Alias(&largest_handle);
[email protected]a896ce32012-01-09 22:04:071180 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201181
[email protected]6d0146c2011-08-04 19:13:041182 AddDownloadItemToHistory(download, db_handle);
1183
1184 // Finalize this download if it finished before the history callback.
1185 if (!download->IsInProgress())
1186 SavePageDownloadFinished(download);
1187}
1188
[email protected]5656f8a2011-11-17 16:12:581189void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]5009b7a2012-02-21 18:47:031190 if (download->IsPersisted()) {
[email protected]2588ea9d2011-08-22 20:59:531191 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501192 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1193 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041194
1195 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071196 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041197 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531198 content::Source<DownloadManager>(this),
1199 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041200 }
1201}
[email protected]da4a5582011-10-17 19:08:061202
[email protected]fc03de22011-12-06 23:28:121203void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061204 delegate_->UpdateItemInPersistentStore(download);
1205 int num_unopened = 0;
1206 for (DownloadMap::iterator it = history_downloads_.begin();
1207 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501208 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061209 ++num_unopened;
1210 }
1211 download_stats::RecordOpensOutstanding(num_unopened);
1212}
[email protected]5656f8a2011-11-17 16:12:581213
[email protected]5948e1a2012-03-10 00:19:181214void DownloadManagerImpl::SetFileManagerForTesting(
1215 DownloadFileManager* file_manager) {
[email protected]5656f8a2011-11-17 16:12:581216 file_manager_ = file_manager;
1217}