blob: 1603f6a6becfb31bf6651f0dd1e065749f395288 [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]5948e1a2012-03-10 00:19:1824#include "content/browser/net/url_request_slow_download_job.h"
[email protected]b3c41c0b2012-03-06 15:48:3225#include "content/browser/renderer_host/render_view_host_impl.h"
[email protected]7324d1d2011-03-01 05:02:1626#include "content/browser/renderer_host/resource_dispatcher_host.h"
27#include "content/browser/tab_contents/tab_contents.h"
[email protected]ccb797302011-12-15 16:55:1128#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4929#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4430#include "content/public/browser/content_browser_client.h"
[email protected]bf3b08a2012-03-08 01:52:3431#include "content/public/browser/download_interrupt_reasons.h"
[email protected]1bd0ef12011-10-20 05:24:1732#include "content/public/browser/download_manager_delegate.h"
[email protected]8da82ea2012-03-11 22:16:5233#include "content/public/browser/download_persistent_store_info.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]27678b2a2012-02-04 22:09:1438#include "net/base/upload_data.h"
initial.commit09911bf2008-07-26 23:55:2939
[email protected]a896ce32012-01-09 22:04:0740// TODO(benjhayden): Change this to DCHECK when we have more debugging
41// information from the next dev cycle, before the next stable/beta branch is
42// cut, in order to prevent unnecessary crashes on those channels. If we still
43// don't have root cause before the dev cycle after the next stable/beta
44// releases, uncomment it out to re-enable debugging checks. Whenever this macro
45// is toggled, the corresponding macro in download_database.cc should also
46// be toggled. When 96627 is fixed, this macro and all its usages can be
47// deleted or permanently changed to DCHECK as appropriate.
48#define CHECK_96627 CHECK
49
[email protected]631bb742011-11-02 11:29:3950using content::BrowserThread;
[email protected]98e814062012-01-27 00:35:4251using content::DownloadId;
[email protected]e582fdd2011-12-20 16:48:1752using content::DownloadItem;
[email protected]8da82ea2012-03-11 22:16:5253using content::DownloadPersistentStoreInfo;
[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]27678b2a2012-02-04 22:09:1460 URLParams(const GURL& url, const GURL& referrer, int64 post_id)
61 : url_(url), referrer_(referrer), post_id_(post_id) {}
[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]fabf36d22011-10-28 21:50:1765};
66
67struct RenderParams {
68 RenderParams(int rpi, int rvi)
69 : render_process_id_(rpi), render_view_id_(rvi) {}
70 int render_process_id_;
71 int render_view_id_;
72};
73
74void BeginDownload(const URLParams& url_params,
[email protected]0d4e30c2012-01-28 00:47:5375 bool prefer_cache,
[email protected]fabf36d22011-10-28 21:50:1776 const DownloadSaveInfo& save_info,
77 ResourceDispatcherHost* resource_dispatcher_host,
78 const RenderParams& render_params,
[email protected]df02aca2012-02-09 21:03:2079 content::ResourceContext* context) {
[email protected]c1ba99842012-01-19 20:56:0580 scoped_ptr<net::URLRequest> request(
81 new net::URLRequest(url_params.url_, resource_dispatcher_host));
[email protected]fabf36d22011-10-28 21:50:1782 request->set_referrer(url_params.referrer_.spec());
[email protected]27678b2a2012-02-04 22:09:1483 if (url_params.post_id_ >= 0) {
84 // The POST in this case does not have an actual body, and only works
85 // when retrieving data from cache. This is done because we don't want
86 // to do a re-POST without user consent, and currently don't have a good
87 // plan on how to display the UI for that.
88 DCHECK(prefer_cache);
89 request->set_method("POST");
90 scoped_refptr<net::UploadData> upload_data = new net::UploadData();
91 upload_data->set_identifier(url_params.post_id_);
92 request->set_upload(upload_data);
93 }
[email protected]c79a0c02011-08-22 22:37:3794 resource_dispatcher_host->BeginDownload(
[email protected]0d4e30c2012-01-28 00:47:5395 request.Pass(), prefer_cache, save_info,
[email protected]8e3ae68c2011-09-16 22:15:4796 DownloadResourceHandler::OnStartedCallback(),
[email protected]fabf36d22011-10-28 21:50:1797 render_params.render_process_id_,
98 render_params.render_view_id_,
[email protected]df02aca2012-02-09 21:03:2099 context);
[email protected]a0ce3282011-08-19 20:49:52100}
101
[email protected]33d22102012-01-25 17:46:53102class MapValueIteratorAdapter {
103 public:
104 explicit MapValueIteratorAdapter(
105 base::hash_map<int64, DownloadItem*>::const_iterator iter)
106 : iter_(iter) {
107 }
108 ~MapValueIteratorAdapter() {}
109
110 DownloadItem* operator*() { return iter_->second; }
111
112 MapValueIteratorAdapter& operator++() {
113 ++iter_;
114 return *this;
115 }
116
117 bool operator!=(const MapValueIteratorAdapter& that) const {
118 return iter_ != that.iter_;
119 }
120
121 private:
122 base::hash_map<int64, DownloadItem*>::const_iterator iter_;
123 // Allow copy and assign.
124};
125
[email protected]5948e1a2012-03-10 00:19:18126void EnsureNoPendingDownloadsOnFile(scoped_refptr<DownloadFileManager> dfm,
127 bool* result) {
128 if (dfm->NumberOfActiveDownloads())
129 *result = false;
130 BrowserThread::PostTask(
131 BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure());
132}
133
134void EnsureNoPendingDownloadsOnIO(bool* result) {
135 if (URLRequestSlowDownloadJob::NumberOutstandingRequests()) {
136 *result = false;
137 BrowserThread::PostTask(
138 BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure());
139 return;
140 }
141
142 scoped_refptr<DownloadFileManager> download_file_manager =
143 ResourceDispatcherHost::Get()->download_file_manager();
144 BrowserThread::PostTask(
145 BrowserThread::FILE, FROM_HERE,
146 base::Bind(&EnsureNoPendingDownloadsOnFile,
147 download_file_manager, result));
148}
149
[email protected]a0ce3282011-08-19 20:49:52150} // namespace
151
[email protected]99907362012-01-11 05:41:40152namespace content {
153
154// static
155DownloadManager* DownloadManager::Create(
[email protected]ef17c9a2012-02-09 05:08:09156 content::DownloadManagerDelegate* delegate,
157 net::NetLog* net_log) {
158 return new DownloadManagerImpl(delegate, net_log);
[email protected]99907362012-01-11 05:41:40159}
160
[email protected]5948e1a2012-03-10 00:19:18161bool DownloadManager::EnsureNoPendingDownloadsForTesting() {
162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
163 bool result = true;
164 BrowserThread::PostTask(
165 BrowserThread::IO, FROM_HERE,
166 base::Bind(&EnsureNoPendingDownloadsOnIO, &result));
167 MessageLoop::current()->Run();
168 return result;
169}
170
[email protected]99907362012-01-11 05:41:40171} // namespace content
172
[email protected]5656f8a2011-11-17 16:12:58173DownloadManagerImpl::DownloadManagerImpl(
[email protected]ef17c9a2012-02-09 05:08:09174 content::DownloadManagerDelegate* delegate,
175 net::NetLog* net_log)
[email protected]5656f8a2011-11-17 16:12:58176 : shutdown_needed_(false),
177 browser_context_(NULL),
178 file_manager_(NULL),
[email protected]5656f8a2011-11-17 16:12:58179 delegate_(delegate),
[email protected]ef17c9a2012-02-09 05:08:09180 largest_db_handle_in_history_(DownloadItem::kUninitializedHandle),
181 net_log_(net_log) {
initial.commit09911bf2008-07-26 23:55:29182}
183
[email protected]5656f8a2011-11-17 16:12:58184DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13185 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29186}
187
[email protected]5656f8a2011-11-17 16:12:58188DownloadId DownloadManagerImpl::GetNextId() {
[email protected]98e814062012-01-27 00:35:42189 return delegate_->GetNextId();
[email protected]2909e342011-10-29 00:46:53190}
191
[email protected]fc03de22011-12-06 23:28:12192bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
193 return delegate_->ShouldOpenDownload(item);
194}
195
196bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
197 return delegate_->ShouldOpenFileBasedOnExtension(path);
198}
199
[email protected]5656f8a2011-11-17 16:12:58200void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50201 VLOG(20) << __FUNCTION__ << "()"
202 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13203 if (!shutdown_needed_)
204 return;
205 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29206
[email protected]75e51b52012-02-04 16:57:54207 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
[email protected]fb4f8d902011-09-16 06:07:08208 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13209
210 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18211 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17212 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
213 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13214 }
initial.commit09911bf2008-07-26 23:55:29215
[email protected]f04182f32010-12-10 19:12:07216 AssertContainersConsistent();
217
218 // Go through all downloads in downloads_. Dangerous ones we need to
219 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09220 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07221 DownloadItem* download = *it;
222
223 // Save iterator from potential erases in this set done by called code.
224 // Iterators after an erasure point are still valid for lists and
225 // associative containers such as sets.
226 it++;
227
[email protected]c09a8fd2011-11-21 19:54:50228 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29229 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07230 // The user hasn't accepted it, so we need to remove it
231 // from the disk. This may or may not result in it being
232 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12233 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07234 // removes and deletes it if it's known to the history service)
235 // so the only thing we know after calling this function is that
236 // the download was deleted if-and-only-if it was removed
237 // from all queues.
[email protected]303077002011-04-19 23:21:01238 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26239 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17240 download->Cancel(false);
241 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29242 }
243 }
244
[email protected]f04182f32010-12-10 19:12:07245 // At this point, all dangerous downloads have had their files removed
246 // and all in progress downloads have been cancelled. We can now delete
247 // anything left.
[email protected]9ccbb372008-10-10 18:50:32248
[email protected]5cd11b6e2011-06-10 20:30:59249 // Copy downloads_ to separate container so as not to set off checks
250 // in DownloadItem destruction.
251 DownloadSet downloads_to_delete;
252 downloads_to_delete.swap(downloads_);
253
initial.commit09911bf2008-07-26 23:55:29254 in_progress_.clear();
[email protected]70850c72011-01-11 17:31:27255 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59256 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59257 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29258
[email protected]41f558fb2012-01-09 22:59:58259 // We'll have nothing more to report to the observers after this point.
260 observers_.Clear();
261
[email protected]6d0146c2011-08-04 19:13:04262 DCHECK(save_page_downloads_.empty());
263
initial.commit09911bf2008-07-26 23:55:29264 file_manager_ = NULL;
[email protected]2588ea9d2011-08-22 20:59:53265 delegate_->Shutdown();
initial.commit09911bf2008-07-26 23:55:29266}
267
[email protected]5656f8a2011-11-17 16:12:58268void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04269 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57270 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58271
[email protected]f04182f32010-12-10 19:12:07272 for (DownloadMap::iterator it = history_downloads_.begin();
273 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50274 if (it->second->IsTemporary() &&
[email protected]fdd2715c2011-12-09 22:24:20275 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57276 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58277 }
[email protected]6aa4a1c02010-01-15 18:49:58278}
279
[email protected]5656f8a2011-11-17 16:12:58280void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04281 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57282 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34283
[email protected]f04182f32010-12-10 19:12:07284 for (DownloadMap::iterator it = history_downloads_.begin();
285 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50286 if (!it->second->IsTemporary() &&
287 (dir_path.empty() || it->second->GetFullPath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57288 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34289 }
[email protected]8ddbd66a2010-05-21 16:38:34290}
291
[email protected]5656f8a2011-11-17 16:12:58292void DownloadManagerImpl::SearchDownloads(const string16& query,
293 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26294 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42295
[email protected]f04182f32010-12-10 19:12:07296 for (DownloadMap::iterator it = history_downloads_.begin();
297 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42298 DownloadItem* download_item = it->second;
299
[email protected]c09a8fd2011-11-21 19:54:50300 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42301 continue;
302
303 // Display Incognito downloads only in Incognito window, and vice versa.
304 // The Incognito Downloads page will get the list of non-Incognito downloads
305 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50306 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42307 continue;
308
309 if (download_item->MatchesQuery(query_lower))
310 result->push_back(download_item);
311 }
[email protected]d3b12902010-08-16 23:39:42312}
313
initial.commit09911bf2008-07-26 23:55:29314// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58315bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03316 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29317 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
318 shutdown_needed_ = true;
319
[email protected]6d0c9fb2011-08-22 19:26:03320 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46321
[email protected]b39e7a88b2012-01-10 21:43:17322 // In test mode, there may be no ResourceDispatcherHost. In this case it's
323 // safe to avoid setting |file_manager_| because we only call a small set of
324 // functions, none of which need it.
[email protected]99907362012-01-11 05:41:40325 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get();
[email protected]b39e7a88b2012-01-10 21:43:17326 if (rdh) {
327 file_manager_ = rdh->download_file_manager();
328 DCHECK(file_manager_);
329 }
initial.commit09911bf2008-07-26 23:55:29330
initial.commit09911bf2008-07-26 23:55:29331 return true;
332}
333
[email protected]aa9881c2011-08-15 18:01:12334// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58335void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35337
[email protected]aa9881c2011-08-15 18:01:12338 if (delegate_->ShouldStartDownload(download_id))
339 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35340}
341
[email protected]5656f8a2011-11-17 16:12:58342void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
344 for (DownloadMap::iterator it = history_downloads_.begin();
345 it != history_downloads_.end(); ++it) {
346 CheckForFileRemoval(it->second);
347 }
348}
349
[email protected]5656f8a2011-11-17 16:12:58350void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
352 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50353 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48354 BrowserThread::PostTask(
355 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58356 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50357 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17358 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48359 }
360}
361
[email protected]5656f8a2011-11-17 16:12:58362void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48363 int64 db_handle, const FilePath& path) {
364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
365 if (!file_util::PathExists(path)) {
366 BrowserThread::PostTask(
367 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58368 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
369 this,
370 db_handle));
[email protected]9fc114672011-06-15 08:17:48371 }
372}
373
[email protected]5656f8a2011-11-17 16:12:58374void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
376 DownloadMap::iterator it = history_downloads_.find(db_handle);
377 if (it != history_downloads_.end()) {
378 DownloadItem* download_item = it->second;
379 download_item->OnDownloadedFileRemoved();
380 }
381}
382
[email protected]443853c62011-12-22 19:22:41383void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29385
[email protected]4cd82f72011-05-23 19:15:01386 DownloadItem* download = GetActiveDownloadItem(download_id);
387 if (!download)
388 return;
389
390 VLOG(20) << __FUNCTION__ << "()"
391 << " download = " << download->DebugString(true);
392
[email protected]c09a8fd2011-11-21 19:54:50393 FilePath suggested_path = download->GetSuggestedPath();
[email protected]4cd82f72011-05-23 19:15:01394
[email protected]c09a8fd2011-11-21 19:54:50395 if (download->PromptUserForSaveLocation()) {
initial.commit09911bf2008-07-26 23:55:29396 // We must ask the user for the place to put the download.
[email protected]a62d42902012-01-24 17:24:38397 WebContents* contents = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:26398
[email protected]795b76a2011-12-14 16:52:53399 FilePath target_path;
400 // If |download| is a potentially dangerous file, then |suggested_path|
401 // contains the intermediate name instead of the final download
402 // filename. The latter is GetTargetName().
[email protected]a62d42902012-01-24 17:24:38403 if (download->GetDangerType() !=
404 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
[email protected]795b76a2011-12-14 16:52:53405 target_path = suggested_path.DirName().Append(download->GetTargetName());
406 else
407 target_path = suggested_path;
[email protected]99cb7f82011-07-28 17:27:26408
[email protected]795b76a2011-12-14 16:52:53409 delegate_->ChooseDownloadPath(contents, target_path,
[email protected]84d57412012-03-03 08:59:55410 download_id);
[email protected]f5920322011-03-24 20:34:16411 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]75e51b52012-02-04 16:57:54412 SelectFileDialogDisplayed(this, download_id));
initial.commit09911bf2008-07-26 23:55:29413 } else {
414 // No prompting for download, just continue with the suggested name.
[email protected]4cd82f72011-05-23 19:15:01415 ContinueDownloadWithPath(download, suggested_path);
initial.commit09911bf2008-07-26 23:55:29416 }
417}
418
[email protected]37757c62011-12-20 20:07:12419content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58420 return browser_context_;
421}
422
423FilePath DownloadManagerImpl::LastDownloadPath() {
424 return last_download_path_;
425}
426
[email protected]ef17c9a2012-02-09 05:08:09427net::BoundNetLog DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41428 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
430
[email protected]ef17c9a2012-02-09 05:08:09431 net::BoundNetLog bound_net_log =
432 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]c09a8fd2011-11-21 19:54:50433 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29434 this, *info, new DownloadRequestHandle(request_handle),
[email protected]ef17c9a2012-02-09 05:08:09435 browser_context_->IsOffTheRecord(), bound_net_log);
[email protected]2909e342011-10-29 00:46:53436 int32 download_id = info->download_id.local();
[email protected]4cd82f72011-05-23 19:15:01437 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]d8472d92011-08-26 20:15:20438
[email protected]a896ce32012-01-09 22:04:07439 CHECK_96627(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29440 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01441 active_downloads_[download_id] = download;
[email protected]ef17c9a2012-02-09 05:08:09442
443 return bound_net_log;
[email protected]c2e76012010-12-23 21:10:29444}
445
[email protected]fc03de22011-12-06 23:28:12446DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
447 const FilePath& main_file_path,
448 const GURL& page_url,
449 bool is_otr,
450 DownloadItem::Observer* observer) {
[email protected]ef17c9a2012-02-09 05:08:09451 net::BoundNetLog bound_net_log =
452 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12453 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09454 this, main_file_path, page_url, is_otr, GetNextId(), bound_net_log);
[email protected]fc03de22011-12-06 23:28:12455
456 download->AddObserver(observer);
457
458 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
459 downloads_.insert(download);
460 save_page_downloads_[download->GetId()] = download;
461
462 // Will notify the observer in the callback.
463 delegate_->AddItemToPersistentStore(download);
464
465 return download;
466}
467
[email protected]795b76a2011-12-14 16:52:53468// For non-safe downloads with no prompting, |chosen_file| is the intermediate
469// path for saving the in-progress download. The final target filename for these
470// is |download->GetTargetName()|. For all other downloads (non-safe downloads
471// for which we have prompted for a save location, and all safe downloads),
472// |chosen_file| is the final target download path.
[email protected]5656f8a2011-11-17 16:12:58473void DownloadManagerImpl::ContinueDownloadWithPath(
474 DownloadItem* download, const FilePath& chosen_file) {
[email protected]ca4b5fa32010-10-09 12:42:18475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01476 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39477
[email protected]c09a8fd2011-11-21 19:54:50478 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29479
[email protected]70850c72011-01-11 17:31:27480 // NOTE(ahendrickson) Eventually |active_downloads_| will replace
481 // |in_progress_|, but we don't want to change the semantics yet.
[email protected]4cd82f72011-05-23 19:15:01482 DCHECK(!ContainsKey(in_progress_, download_id));
[email protected]70850c72011-01-11 17:31:27483 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01484 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27485
[email protected]4cd82f72011-05-23 19:15:01486 // Make sure the initial file name is set only once.
[email protected]fdd2715c2011-12-09 22:24:20487 DCHECK(download->GetFullPath().empty());
[email protected]4cd82f72011-05-23 19:15:01488 download->OnPathDetermined(chosen_file);
[email protected]4cd82f72011-05-23 19:15:01489
490 VLOG(20) << __FUNCTION__ << "()"
491 << " download = " << download->DebugString(true);
492
493 in_progress_[download_id] = download;
initial.commit09911bf2008-07-26 23:55:29494
[email protected]adb2f3d12011-01-23 16:24:54495 // Rename to intermediate name.
[email protected]f5920322011-03-24 20:34:16496 FilePath download_path;
[email protected]385e93182012-01-30 17:11:03497 if (download->GetDangerType() !=
498 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
499 if (download->PromptUserForSaveLocation()) {
500 // When we prompt the user, we overwrite the FullPath with what the user
501 // wanted to use. Construct a file path using the previously determined
502 // intermediate filename and the new path.
503 // TODO(asanka): This can trample an in-progress download in the new
504 // target directory if it was using the same intermediate name.
505 FilePath file_name = download->GetSuggestedPath().BaseName();
506 download_path = download->GetFullPath().DirName().Append(file_name);
507 } else {
508 // The download's name is already set to an intermediate name, so no need
509 // to override.
510 download_path = download->GetFullPath();
511 }
512 } else {
513 // The download is a safe download. We need to rename it to its
514 // intermediate path. The final name after user confirmation will be set
515 // from DownloadItem::OnDownloadCompleting.
516 download_path = delegate_->GetIntermediatePath(download->GetFullPath());
517 }
[email protected]594cd7d2010-07-21 03:23:56518
[email protected]f5920322011-03-24 20:34:16519 BrowserThread::PostTask(
520 BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17521 base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
[email protected]fc03de22011-12-06 23:28:12522 file_manager_, download->GetGlobalId(),
523 download_path));
[email protected]f5920322011-03-24 20:34:16524
525 download->Rename(download_path);
526
[email protected]2588ea9d2011-08-22 20:59:53527 delegate_->AddItemToPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29528}
529
[email protected]443853c62011-12-22 19:22:41530void DownloadManagerImpl::UpdateDownload(int32 download_id,
531 int64 bytes_so_far,
532 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00533 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27534 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
535 DownloadMap::iterator it = active_downloads_.find(download_id);
536 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29537 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26538 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41539 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]2588ea9d2011-08-22 20:59:53540 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27541 }
initial.commit09911bf2008-07-26 23:55:29542 }
543}
544
[email protected]5656f8a2011-11-17 16:12:58545void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
546 int64 size,
547 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50549 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
550 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32552
[email protected]c4f02c42011-01-24 21:55:06553 // If it's not in active_downloads_, that means it was cancelled; just
554 // ignore the notification.
555 if (active_downloads_.count(download_id) == 0)
556 return;
557
[email protected]adb2f3d12011-01-23 16:24:54558 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37559 download->OnAllDataSaved(size, hash);
[email protected]b09f1282011-09-14 00:37:45560
[email protected]fc03de22011-12-06 23:28:12561 download->MaybeCompleteDownload();
[email protected]adb2f3d12011-01-23 16:24:54562}
[email protected]9ccbb372008-10-10 18:50:32563
[email protected]fc03de22011-12-06 23:28:12564void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]a896ce32012-01-09 22:04:07565 // TODO(rdsmith): Change to DCHECK after http://crbug.com/96627 resolved.
[email protected]c09a8fd2011-11-21 19:54:50566 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]7d413112011-06-16 18:50:17567 CHECK(!ContainsKey(downloads_, download));
[email protected]c09a8fd2011-11-21 19:54:50568 CHECK(!ContainsKey(active_downloads_, download->GetId()));
569 CHECK(!ContainsKey(in_progress_, download->GetId()));
570 CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17571 return;
572 }
573
574 // Should be in downloads_ if we're not REMOVING.
575 CHECK(ContainsKey(downloads_, download));
576
577 // Check history_downloads_ consistency.
[email protected]5009b7a2012-02-21 18:47:03578 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50579 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17580 } else {
[email protected]fc03de22011-12-06 23:28:12581 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17582 it != history_downloads_.end(); ++it) {
[email protected]a896ce32012-01-09 22:04:07583 CHECK_96627(it->second != download);
[email protected]7d413112011-06-16 18:50:17584 }
585 }
586
[email protected]c09a8fd2011-11-21 19:54:50587 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34588 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50589 if (ContainsKey(active_downloads_, download->GetId())) {
[email protected]5009b7a2012-02-21 18:47:03590 if (download->IsPersisted())
[email protected]c09a8fd2011-11-21 19:54:50591 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
592 if (DownloadItem::IN_PROGRESS != download->GetState())
593 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07594 }
[email protected]c09a8fd2011-11-21 19:54:50595 if (DownloadItem::IN_PROGRESS == download->GetState())
596 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59597}
598
[email protected]5656f8a2011-11-17 16:12:58599bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54600 // If we don't have all the data, the download is not ready for
601 // completion.
[email protected]c09a8fd2011-11-21 19:54:50602 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54603 return false;
[email protected]6a7fb042010-02-01 16:30:47604
[email protected]9d7ef802011-02-25 19:03:35605 // If the download is dangerous, but not yet validated, it's not ready for
606 // completion.
[email protected]c09a8fd2011-11-21 19:54:50607 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35608 return false;
609
[email protected]adb2f3d12011-01-23 16:24:54610 // If the download isn't active (e.g. has been cancelled) it's not
611 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50612 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54613 return false;
614
615 // If the download hasn't been inserted into the history system
616 // (which occurs strictly after file name determination, intermediate
617 // file rename, and UI display) then it's not ready for completion.
[email protected]5009b7a2012-02-21 18:47:03618 if (!download->IsPersisted())
[email protected]7054b592011-06-22 14:46:42619 return false;
620
621 return true;
[email protected]adb2f3d12011-01-23 16:24:54622}
623
[email protected]5656f8a2011-11-17 16:12:58624void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
626 VLOG(20) << __FUNCTION__ << "()" << " download = "
627 << download->DebugString(false);
628
629 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32630 return;
[email protected]9ccbb372008-10-10 18:50:32631
[email protected]adb2f3d12011-01-23 16:24:54632 // TODO(rdsmith): DCHECK that we only pass through this point
633 // once per download. The natural way to do this is by a state
634 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56635
[email protected]adb2f3d12011-01-23 16:24:54636 // Confirm we're in the proper set of states to be here;
[email protected]9d7ef802011-02-25 19:03:35637 // in in_progress_, have all data, have a history handle, (validated or safe).
[email protected]c09a8fd2011-11-21 19:54:50638 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
639 DCHECK_EQ(1u, in_progress_.count(download->GetId()));
640 DCHECK(download->AllDataSaved());
[email protected]5009b7a2012-02-21 18:47:03641 DCHECK(download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50642 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54643
[email protected]c2918652011-11-01 18:50:23644 // Give the delegate a chance to override.
645 if (!delegate_->ShouldCompleteDownload(download))
646 return;
647
[email protected]adb2f3d12011-01-23 16:24:54648 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
649 << download->DebugString(false);
650
651 // Remove the id from in_progress
[email protected]c09a8fd2011-11-21 19:54:50652 in_progress_.erase(download->GetId());
[email protected]adb2f3d12011-01-23 16:24:54653
[email protected]2588ea9d2011-08-22 20:59:53654 delegate_->UpdateItemInPersistentStore(download);
[email protected]adb2f3d12011-01-23 16:24:54655
[email protected]f5920322011-03-24 20:34:16656 // Finish the download.
[email protected]48837962011-04-19 17:03:29657 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32658}
659
[email protected]fc03de22011-12-06 23:28:12660void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27661 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21662 DCHECK(download);
[email protected]2588ea9d2011-08-22 20:59:53663 delegate_->UpdateItemInPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12664 active_downloads_.erase(download->GetId());
665 AssertStateConsistent(download);
[email protected]70850c72011-01-11 17:31:27666}
667
[email protected]5656f8a2011-11-17 16:12:58668void DownloadManagerImpl::OnDownloadRenamedToFinalName(
669 int download_id,
670 const FilePath& full_path,
671 int uniquifier) {
[email protected]da6e3922010-11-24 21:45:50672 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
[email protected]f5920322011-03-24 20:34:16673 << " full_path = \"" << full_path.value() << "\""
674 << " uniquifier = " << uniquifier;
[email protected]ca4b5fa32010-10-09 12:42:18675 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]f5920322011-03-24 20:34:16676
[email protected]2e030682010-07-23 19:45:36677 DownloadItem* item = GetDownloadItem(download_id);
678 if (!item)
679 return;
[email protected]6cade212008-12-03 00:32:22680
[email protected]a62d42902012-01-24 17:24:38681 if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
[email protected]795b76a2011-12-14 16:52:53682 item->PromptUserForSaveLocation()) {
683 DCHECK_EQ(0, uniquifier)
684 << "We should not uniquify user supplied filenames or safe filenames "
685 "that have already been uniquified.";
[email protected]8fa1eeb52011-04-13 14:18:02686 }
687
[email protected]fabf36d22011-10-28 21:50:17688 BrowserThread::PostTask(
689 BrowserThread::FILE, FROM_HERE,
690 base::Bind(&DownloadFileManager::CompleteDownload,
[email protected]c09a8fd2011-11-21 19:54:50691 file_manager_, item->GetGlobalId()));
[email protected]9ccbb372008-10-10 18:50:32692
[email protected]f5920322011-03-24 20:34:16693 if (uniquifier)
[email protected]c09a8fd2011-11-21 19:54:50694 item->SetPathUniquifier(uniquifier);
[email protected]9ccbb372008-10-10 18:50:32695
[email protected]f5920322011-03-24 20:34:16696 item->OnDownloadRenamedToFinalName(full_path);
[email protected]2588ea9d2011-08-22 20:59:53697 delegate_->UpdatePathForItemInPersistentStore(item, full_path);
initial.commit09911bf2008-07-26 23:55:29698}
699
[email protected]5656f8a2011-11-17 16:12:58700void DownloadManagerImpl::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17701 DownloadItem* download = GetActiveDownload(download_id);
702 // A cancel at the right time could remove the download from the
703 // |active_downloads_| map before we get here.
704 if (!download)
705 return;
706
707 download->Cancel(true);
708}
709
[email protected]fc03de22011-12-06 23:28:12710void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20711 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20712
713 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50714 << " download = " << download->DebugString(true);
715
[email protected]93af2272011-09-21 18:29:17716 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21717 // This function is called from the DownloadItem, so DI state
718 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12719 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29720
[email protected]15d90ba2011-11-03 03:41:55721 if (file_manager_)
722 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29723}
724
[email protected]bf3b08a2012-03-08 01:52:34725void DownloadManagerImpl::OnDownloadInterrupted(
726 int32 download_id,
727 int64 size,
728 const std::string& hash_state,
729 content::DownloadInterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21730 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
731
732 DownloadItem* download = GetActiveDownload(download_id);
733 if (!download)
734 return;
735
[email protected]be76b7e2011-10-13 12:57:57736 VLOG(20) << __FUNCTION__ << "()"
737 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50738 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21739 << " size = " << size
740 << " download = " << download->DebugString(true);
741
[email protected]93af2272011-09-21 18:29:17742 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41743 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17744 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21745}
746
[email protected]5656f8a2011-11-17 16:12:58747DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26748 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
749 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26750 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21751 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26752
753 DownloadItem* download = it->second;
754
[email protected]47a881b2011-08-29 22:59:21755 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50756 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01757
[email protected]47a881b2011-08-29 22:59:21758 return download;
759}
[email protected]54610672011-07-18 18:24:43760
[email protected]5656f8a2011-11-17 16:12:58761void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17762 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
763 DCHECK(download);
764
765 // Clean up will happen when the history system create callback runs if we
766 // don't have a valid db_handle yet.
[email protected]5009b7a2012-02-21 18:47:03767 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50768 in_progress_.erase(download->GetId());
769 active_downloads_.erase(download->GetId());
[email protected]93af2272011-09-21 18:29:17770 delegate_->UpdateItemInPersistentStore(download);
771 }
772}
773
[email protected]fd3a82832012-01-19 20:35:12774bool DownloadManagerImpl::GenerateFileHash() {
775 return delegate_->GenerateFileHash();
776}
777
[email protected]5656f8a2011-11-17 16:12:58778content::DownloadManagerDelegate* DownloadManagerImpl::delegate() const {
779 return delegate_;
780}
781
782void DownloadManagerImpl::SetDownloadManagerDelegate(
[email protected]1bd0ef12011-10-20 05:24:17783 content::DownloadManagerDelegate* delegate) {
[email protected]9bb54ee2011-10-12 17:43:35784 delegate_ = delegate;
785}
786
[email protected]5656f8a2011-11-17 16:12:58787int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04788 const DownloadVector& pending_deletes) {
789 if (pending_deletes.empty())
790 return 0;
791
792 // Delete from internal maps.
793 for (DownloadVector::const_iterator it = pending_deletes.begin();
794 it != pending_deletes.end();
795 ++it) {
796 DownloadItem* download = *it;
797 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50798 history_downloads_.erase(download->GetDbHandle());
799 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04800 downloads_.erase(download);
801 }
802
803 // Tell observers to refresh their views.
804 NotifyModelChanged();
805
806 // Delete the download items themselves.
807 const int num_deleted = static_cast<int>(pending_deletes.size());
808 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
809 return num_deleted;
810}
811
[email protected]fc03de22011-12-06 23:28:12812void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
813 if (history_downloads_.find(download->GetDbHandle()) ==
814 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17815 return;
816
817 // Make history update.
[email protected]93af2272011-09-21 18:29:17818 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29819
820 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04821 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07822 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29823}
824
[email protected]fd3a82832012-01-19 20:35:12825int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
826 base::Time remove_end) {
[email protected]2588ea9d2011-08-22 20:59:53827 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29828
[email protected]a312a442010-12-15 23:40:33829 // All downloads visible to the user will be in the history,
830 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04831 DownloadVector pending_deletes;
832 for (DownloadMap::const_iterator it = history_downloads_.begin();
833 it != history_downloads_.end();
834 ++it) {
initial.commit09911bf2008-07-26 23:55:29835 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50836 if (download->GetStartTime() >= remove_begin &&
837 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04838 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12839 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28840 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29841 }
initial.commit09911bf2008-07-26 23:55:29842 }
[email protected]6d0146c2011-08-04 19:13:04843 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29844}
845
[email protected]fd3a82832012-01-19 20:35:12846int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59847 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29848}
849
[email protected]5656f8a2011-11-17 16:12:58850int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06851 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12852 // The null times make the date range unbounded.
853 return RemoveDownloadsBetween(base::Time(), base::Time());
854}
855
initial.commit09911bf2008-07-26 23:55:29856// Initiate a download of a specific URL. We send the request to the
857// ResourceDispatcherHost, and let it send us responses like a regular
858// download.
[email protected]0d4e30c2012-01-28 00:47:53859void DownloadManagerImpl::DownloadUrl(
860 const GURL& url,
861 const GURL& referrer,
862 const std::string& referrer_charset,
863 bool prefer_cache,
[email protected]27678b2a2012-02-04 22:09:14864 int64 post_id,
[email protected]0d4e30c2012-01-28 00:47:53865 const DownloadSaveInfo& save_info,
866 WebContents* web_contents) {
[email protected]c79a0c02011-08-22 22:37:37867 ResourceDispatcherHost* resource_dispatcher_host =
[email protected]99907362012-01-11 05:41:40868 ResourceDispatcherHost::Get();
[email protected]443853c62011-12-22 19:22:41869
[email protected]ed24fad2011-05-10 22:44:01870 // We send a pointer to content::ResourceContext, instead of the usual
871 // reference, so that a copy of the object isn't made.
[email protected]fabf36d22011-10-28 21:50:17872 // base::Bind can't handle 7 args, so we use URLParams and RenderParams.
873 BrowserThread::PostTask(
874 BrowserThread::IO, FROM_HERE,
[email protected]0d4e30c2012-01-28 00:47:53875 base::Bind(
876 &BeginDownload,
[email protected]27678b2a2012-02-04 22:09:14877 URLParams(url, referrer, post_id),
[email protected]0d4e30c2012-01-28 00:47:53878 prefer_cache,
879 save_info,
880 resource_dispatcher_host,
[email protected]fbc5e5f92012-01-02 06:08:32881 RenderParams(web_contents->GetRenderProcessHost()->GetID(),
[email protected]9f76c1e2012-03-05 15:15:58882 web_contents->GetRenderViewHost()->GetRoutingID()),
[email protected]df02aca2012-02-09 21:03:20883 web_contents->GetBrowserContext()->GetResourceContext()));
initial.commit09911bf2008-07-26 23:55:29884}
885
[email protected]5656f8a2011-11-17 16:12:58886void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29887 observers_.AddObserver(observer);
[email protected]a1e41e72012-02-22 17:41:25888 // TODO: It is the responsibility of the observers to query the
889 // DownloadManager. Remove the following call from here and update all
890 // observers.
[email protected]75e51b52012-02-04 16:57:54891 observer->ModelChanged(this);
initial.commit09911bf2008-07-26 23:55:29892}
893
[email protected]5656f8a2011-11-17 16:12:58894void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29895 observers_.RemoveObserver(observer);
896}
897
[email protected]84d57412012-03-03 08:59:55898void DownloadManagerImpl::FileSelected(const FilePath& path,
899 int32 download_id) {
[email protected]4cd82f72011-05-23 19:15:01900 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
901
[email protected]4cd82f72011-05-23 19:15:01902 DownloadItem* download = GetActiveDownloadItem(download_id);
903 if (!download)
904 return;
905 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
906 << " download = " << download->DebugString(true);
907
[email protected]c09a8fd2011-11-21 19:54:50908 if (download->PromptUserForSaveLocation())
[email protected]7ae7c2cb2009-01-06 23:31:41909 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35910
[email protected]4cd82f72011-05-23 19:15:01911 // Make sure the initial file name is set only once.
912 ContinueDownloadWithPath(download, path);
initial.commit09911bf2008-07-26 23:55:29913}
914
[email protected]84d57412012-03-03 08:59:55915void DownloadManagerImpl::FileSelectionCanceled(int32 download_id) {
initial.commit09911bf2008-07-26 23:55:29916 // The user didn't pick a place to save the file, so need to cancel the
917 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01918 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01919
920 DownloadItem* download = GetActiveDownloadItem(download_id);
921 if (!download)
922 return;
923
924 VLOG(20) << __FUNCTION__ << "()"
925 << " download = " << download->DebugString(true);
926
[email protected]8f8bc112012-02-22 12:36:31927 download->Cancel(true);
[email protected]4cd82f72011-05-23 19:15:01928}
929
initial.commit09911bf2008-07-26 23:55:29930// Operations posted to us from the history service ----------------------------
931
932// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25933// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58934void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25935 std::vector<DownloadPersistentStoreInfo>* entries) {
[email protected]d8472d92011-08-26 20:15:20936 // TODO(rdsmith): Remove this and related logic when
[email protected]a896ce32012-01-09 22:04:07937 // http://crbug.com/96627 is fixed.
[email protected]d8472d92011-08-26 20:15:20938 largest_db_handle_in_history_ = 0;
939
initial.commit09911bf2008-07-26 23:55:29940 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]deb40832012-02-23 15:41:37941 int64 db_handle = entries->at(i).db_handle;
942 base::debug::Alias(&db_handle);
943 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
944
[email protected]ef17c9a2012-02-09 05:08:09945 net::BoundNetLog bound_net_log =
946 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12947 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09948 this, GetNextId(), entries->at(i), bound_net_log);
[email protected]f04182f32010-12-10 19:12:07949 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50950 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50951 VLOG(20) << __FUNCTION__ << "()" << i << ">"
952 << " download = " << download->DebugString(true);
[email protected]d8472d92011-08-26 20:15:20953
[email protected]c09a8fd2011-11-21 19:54:50954 if (download->GetDbHandle() > largest_db_handle_in_history_)
955 largest_db_handle_in_history_ = download->GetDbHandle();
initial.commit09911bf2008-07-26 23:55:29956 }
[email protected]b0ab1d42010-02-24 19:29:28957 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48958 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29959}
960
[email protected]5656f8a2011-11-17 16:12:58961void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
962 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27963 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d2a8fb72010-01-21 05:31:42964
[email protected]a896ce32012-01-09 22:04:07965 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]1e9fe7ff2011-06-24 17:37:33966 // is fixed.
[email protected]2588ea9d2011-08-22 20:59:53967 CHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33968
[email protected]da4a5582011-10-17 19:08:06969 download_stats::RecordHistorySize(history_downloads_.size());
970
[email protected]5009b7a2012-02-21 18:47:03971 DCHECK(!download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50972 download->SetDbHandle(db_handle);
[email protected]5009b7a2012-02-21 18:47:03973 download->SetIsPersisted();
[email protected]5bcd73eb2011-03-23 21:14:02974
[email protected]a896ce32012-01-09 22:04:07975 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]d8472d92011-08-26 20:15:20976 // is fixed.
[email protected]a896ce32012-01-09 22:04:07977 CHECK_96627(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]c09a8fd2011-11-21 19:54:50978 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04979
980 // Show in the appropriate browser UI.
981 // This includes buttons to save or cancel, for a dangerous download.
982 ShowDownloadInBrowser(download);
983
984 // Inform interested objects about the new download.
985 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19986}
987
[email protected]2588ea9d2011-08-22 20:59:53988
[email protected]5656f8a2011-11-17 16:12:58989void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
990 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53991 if (save_page_downloads_.count(download_id)) {
992 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
993 } else if (active_downloads_.count(download_id)) {
994 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
995 }
996 // It's valid that we don't find a matching item, i.e. on shutdown.
997}
998
[email protected]f9a45b02011-06-30 23:49:19999// Once the new DownloadItem's creation info has been committed to the history
1000// service, we associate the DownloadItem with the db handle, update our
1001// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:581002void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
1003 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:191004 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:451005 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:171006 if (!download)
[email protected]19420cc2011-07-18 17:43:451007 return;
[email protected]54610672011-07-18 18:24:431008
1009 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
1010 << " download_id = " << download_id
1011 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:191012
[email protected]a896ce32012-01-09 22:04:071013 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201014 int64 largest_handle = largest_db_handle_in_history_;
1015 base::debug::Alias(&largest_handle);
[email protected]e5107ce2011-09-19 20:36:131016 int32 matching_item_download_id
1017 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:501018 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:131019 base::debug::Alias(&matching_item_download_id);
1020
[email protected]a896ce32012-01-09 22:04:071021 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201022
[email protected]f9a45b02011-06-30 23:49:191023 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:291024
[email protected]93af2272011-09-21 18:29:171025 // If the download is still in progress, try to complete it.
1026 //
1027 // Otherwise, download has been cancelled or interrupted before we've
1028 // received the DB handle. We post one final message to the history
1029 // service so that it can be properly in sync with the DownloadItem's
1030 // completion status, and also inform any observers so that they get
1031 // more than just the start notification.
1032 if (download->IsInProgress()) {
1033 MaybeCompleteDownload(download);
1034 } else {
[email protected]a896ce32012-01-09 22:04:071035 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/96627
[email protected]93af2272011-09-21 18:29:171036 // is fixed.
1037 CHECK(download->IsCancelled())
1038 << " download = " << download->DebugString(true);
1039 in_progress_.erase(download_id);
1040 active_downloads_.erase(download_id);
1041 delegate_->UpdateItemInPersistentStore(download);
1042 download->UpdateObservers();
1043 }
initial.commit09911bf2008-07-26 23:55:291044}
1045
[email protected]5656f8a2011-11-17 16:12:581046void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]8ddbd66a2010-05-21 16:38:341047 // The 'contents' may no longer exist if the user closed the tab before we
[email protected]99cb7f82011-07-28 17:27:261048 // get this start completion event.
[email protected]a62d42902012-01-24 17:24:381049 WebContents* content = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:261050
1051 // If the contents no longer exists, we ask the embedder to suggest another
1052 // tab.
[email protected]da1a27b2011-07-29 23:16:331053 if (!content)
[email protected]ef9572e2012-01-04 22:14:121054 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:531055
[email protected]0bfbf882011-12-22 18:19:271056 if (content && content->GetDelegate())
1057 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:531058}
1059
[email protected]5656f8a2011-11-17 16:12:581060int DownloadManagerImpl::InProgressCount() const {
1061 return static_cast<int>(in_progress_.size());
1062}
1063
[email protected]6cade212008-12-03 00:32:221064// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581065void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411066 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381067}
[email protected]b0ab1d42010-02-24 19:29:281068
[email protected]5656f8a2011-11-17 16:12:581069void DownloadManagerImpl::NotifyModelChanged() {
[email protected]75e51b52012-02-04 16:57:541070 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged(this));
[email protected]b0ab1d42010-02-24 19:29:281071}
1072
[email protected]5656f8a2011-11-17 16:12:581073DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011074 // The |history_downloads_| map is indexed by the download's db_handle,
1075 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071076 for (DownloadMap::iterator it = history_downloads_.begin();
1077 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361078 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501079 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361080 return item;
1081 }
1082 return NULL;
1083}
1084
[email protected]5656f8a2011-11-17 16:12:581085DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361086 if (ContainsKey(active_downloads_, download_id))
1087 return active_downloads_[download_id];
1088 return NULL;
[email protected]4cd82f72011-05-23 19:15:011089}
1090
[email protected]57fd1252010-12-23 17:24:091091// Confirm that everything in all maps is also in |downloads_|, and that
1092// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581093void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071094#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091095 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041096 const DownloadMap* input_maps[] = {&active_downloads_,
1097 &history_downloads_,
1098 &save_page_downloads_};
1099 DownloadSet active_set, history_set, save_page_set;
1100 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1101 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091102 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1103 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041104 it != input_maps[i]->end(); ++it) {
1105 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071106 }
1107 }
[email protected]57fd1252010-12-23 17:24:091108
1109 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091110 DownloadSet downloads_union;
1111 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1112 DownloadSet remainder;
1113 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1114 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1115 downloads_.begin(), downloads_.end(),
1116 insert_it);
1117 DCHECK(remainder.empty());
1118 std::insert_iterator<DownloadSet>
1119 insert_union(downloads_union, downloads_union.end());
1120 std::set_union(downloads_union.begin(), downloads_union.end(),
1121 all_sets[i]->begin(), all_sets[i]->end(),
1122 insert_union);
1123 }
1124
1125 // Is everything in downloads_ present in one of the other sets?
1126 DownloadSet remainder;
1127 std::insert_iterator<DownloadSet>
1128 insert_remainder(remainder, remainder.begin());
1129 std::set_difference(downloads_.begin(), downloads_.end(),
1130 downloads_union.begin(), downloads_union.end(),
1131 insert_remainder);
1132 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071133#endif
1134}
1135
[email protected]6d0146c2011-08-04 19:13:041136// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531137// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041138// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531139// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1140// that the history event is update regardless of the order in which these two
1141// events complete.
[email protected]6d0146c2011-08-04 19:13:041142// If something removes the download item from the download manager (Remove,
1143// Shutdown) the result will be that the SavePage system will not be able to
1144// properly update the download item (which no longer exists) or the download
1145// history, but the action will complete properly anyway. This may lead to the
1146// history entry being wrong on a reload of chrome (specifically in the case of
1147// Initiation -> History Callback -> Removal -> Completion), but there's no way
1148// to solve that without canceling on Remove (which would then update the DB).
1149
[email protected]5656f8a2011-11-17 16:12:581150void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1151 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1153
1154 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1155 // This can happen if the download manager is shutting down and all maps
1156 // have been cleared.
1157 if (it == save_page_downloads_.end())
1158 return;
1159
1160 DownloadItem* download = it->second;
1161 if (!download) {
1162 NOTREACHED();
1163 return;
1164 }
1165
[email protected]a896ce32012-01-09 22:04:071166 // TODO(rdsmith): Remove after http://crbug.com/96627 resolved.
[email protected]d8472d92011-08-26 20:15:201167 int64 largest_handle = largest_db_handle_in_history_;
1168 base::debug::Alias(&largest_handle);
[email protected]a896ce32012-01-09 22:04:071169 CHECK_96627(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201170
[email protected]6d0146c2011-08-04 19:13:041171 AddDownloadItemToHistory(download, db_handle);
1172
1173 // Finalize this download if it finished before the history callback.
1174 if (!download->IsInProgress())
1175 SavePageDownloadFinished(download);
1176}
1177
[email protected]5656f8a2011-11-17 16:12:581178void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]5009b7a2012-02-21 18:47:031179 if (download->IsPersisted()) {
[email protected]2588ea9d2011-08-22 20:59:531180 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501181 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1182 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041183
1184 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071185 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041186 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531187 content::Source<DownloadManager>(this),
1188 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041189 }
1190}
[email protected]da4a5582011-10-17 19:08:061191
[email protected]fc03de22011-12-06 23:28:121192void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]da4a5582011-10-17 19:08:061193 delegate_->UpdateItemInPersistentStore(download);
1194 int num_unopened = 0;
1195 for (DownloadMap::iterator it = history_downloads_.begin();
1196 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501197 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061198 ++num_unopened;
1199 }
1200 download_stats::RecordOpensOutstanding(num_unopened);
1201}
[email protected]5656f8a2011-11-17 16:12:581202
[email protected]5948e1a2012-03-10 00:19:181203void DownloadManagerImpl::SetFileManagerForTesting(
1204 DownloadFileManager* file_manager) {
[email protected]5656f8a2011-11-17 16:12:581205 file_manager_ = file_manager;
1206}