blob: 6b1875d205af22632300ecacfc074e08ce5a0fb2 [file] [log] [blame]
[email protected]0afff032012-01-06 20:55:001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]5656f8a2011-11-17 16:12:585#include "content/browser/download/download_manager_impl.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]e7557f172011-08-19 23:42:017#include <iterator>
8
[email protected]eda58402011-09-21 19:32:029#include "base/bind.h"
[email protected]2041cf342010-02-19 03:15:5910#include "base/callback.h"
[email protected]c6944272012-01-06 22:12:2811#include "base/debug/alias.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/file_util.h"
[email protected]503d03872011-05-06 08:36:2613#include "base/i18n/case_conversion.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/logging.h"
[email protected]7286e3fc2011-07-19 22:13:2415#include "base/stl_util.h"
[email protected]eda58402011-09-21 19:32:0216#include "base/stringprintf.h"
17#include "base/synchronization/lock.h"
18#include "base/sys_string_conversions.h"
[email protected]d2a8fb72010-01-21 05:31:4219#include "build/build_config.h"
[email protected]71bf3f5e2011-08-15 21:05:2220#include "content/browser/download/download_create_info.h"
21#include "content/browser/download/download_file_manager.h"
[email protected]c09a8fd2011-11-21 19:54:5022#include "content/browser/download/download_item_impl.h"
[email protected]da4a5582011-10-17 19:08:0623#include "content/browser/download/download_stats.h"
[email protected]b3c41c0b2012-03-06 15:48:3224#include "content/browser/renderer_host/render_view_host_impl.h"
[email protected]ea114722012-03-12 01:11:2525#include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
[email protected]93ddb3c2012-04-11 21:44:2926#include "content/browser/web_contents/web_contents_impl.h"
[email protected]ccb797302011-12-15 16:55:1127#include "content/public/browser/browser_context.h"
[email protected]c38831a12011-10-28 12:44:4928#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4429#include "content/public/browser/content_browser_client.h"
[email protected]bf3b08a2012-03-08 01:52:3430#include "content/public/browser/download_interrupt_reasons.h"
[email protected]1bd0ef12011-10-20 05:24:1731#include "content/public/browser/download_manager_delegate.h"
[email protected]8da82ea2012-03-11 22:16:5232#include "content/public/browser/download_persistent_store_info.h"
[email protected]c5a5c0842012-05-04 20:05:1433#include "content/public/browser/download_url_parameters.h"
[email protected]ad50def52011-10-19 23:17:0734#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1635#include "content/public/browser/notification_types.h"
[email protected]f3b1a082011-11-18 00:34:3036#include "content/public/browser/render_process_host.h"
[email protected]0bfbf882011-12-22 18:19:2737#include "content/public/browser/web_contents_delegate.h"
[email protected]c5a5c0842012-05-04 20:05:1438#include "net/base/load_flags.h"
[email protected]27678b2a2012-02-04 22:09:1439#include "net/base/upload_data.h"
[email protected]f859eba2012-05-30 17:22:4940#include "webkit/glue/webkit_glue.h"
initial.commit09911bf2008-07-26 23:55:2941
[email protected]631bb742011-11-02 11:29:3942using content::BrowserThread;
[email protected]98e814062012-01-27 00:35:4243using content::DownloadId;
[email protected]e582fdd2011-12-20 16:48:1744using content::DownloadItem;
[email protected]8da82ea2012-03-11 22:16:5245using content::DownloadPersistentStoreInfo;
[email protected]ea114722012-03-12 01:11:2546using content::ResourceDispatcherHostImpl;
[email protected]2a6bc3e2011-12-28 23:51:3347using content::WebContents;
[email protected]631bb742011-11-02 11:29:3948
[email protected]a0ce3282011-08-19 20:49:5249namespace {
50
[email protected]c5a5c0842012-05-04 20:05:1451void BeginDownload(content::DownloadUrlParameters* params) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
53 // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and
54 // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so
55 // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4.
56 content::ResourceDispatcherHostImpl* resource_dispatcher_host =
57 static_cast<content::ResourceDispatcherHostImpl*>(
58 params->resource_dispatcher_host());
59 scoped_ptr<net::URLRequest> request(new net::URLRequest(
60 params->url(), resource_dispatcher_host));
[email protected]f859eba2012-05-30 17:22:4961 request->set_referrer(params->referrer().url.spec());
62 webkit_glue::ConfigureURLRequestForReferrerPolicy(
63 request.get(), params->referrer().policy);
[email protected]c5a5c0842012-05-04 20:05:1464 request->set_load_flags(request->load_flags() | params->load_flags());
65 request->set_method(params->method());
66 if (!params->post_body().empty())
67 request->AppendBytesToUpload(params->post_body().data(),
68 params->post_body().size());
69 if (params->post_id() >= 0) {
[email protected]27678b2a2012-02-04 22:09:1470 // The POST in this case does not have an actual body, and only works
71 // when retrieving data from cache. This is done because we don't want
72 // to do a re-POST without user consent, and currently don't have a good
73 // plan on how to display the UI for that.
[email protected]c5a5c0842012-05-04 20:05:1474 DCHECK(params->prefer_cache());
75 DCHECK(params->method() == "POST");
[email protected]27678b2a2012-02-04 22:09:1476 scoped_refptr<net::UploadData> upload_data = new net::UploadData();
[email protected]c5a5c0842012-05-04 20:05:1477 upload_data->set_identifier(params->post_id());
[email protected]27678b2a2012-02-04 22:09:1478 request->set_upload(upload_data);
79 }
[email protected]c5a5c0842012-05-04 20:05:1480 for (content::DownloadUrlParameters::RequestHeadersType::const_iterator iter
81 = params->request_headers_begin();
82 iter != params->request_headers_end();
83 ++iter) {
84 request->SetExtraRequestHeaderByName(
85 iter->first, iter->second, false/*overwrite*/);
86 }
[email protected]c79a0c02011-08-22 22:37:3787 resource_dispatcher_host->BeginDownload(
[email protected]ea114722012-03-12 01:11:2588 request.Pass(),
[email protected]a53e2f92012-05-15 15:27:0689 params->content_initiated(),
[email protected]c5a5c0842012-05-04 20:05:1490 params->resource_context(),
91 params->render_process_host_id(),
92 params->render_view_host_routing_id(),
93 params->prefer_cache(),
94 params->save_info(),
95 params->callback());
[email protected]a0ce3282011-08-19 20:49:5296}
97
[email protected]33d22102012-01-25 17:46:5398class MapValueIteratorAdapter {
99 public:
100 explicit MapValueIteratorAdapter(
101 base::hash_map<int64, DownloadItem*>::const_iterator iter)
102 : iter_(iter) {
103 }
104 ~MapValueIteratorAdapter() {}
105
106 DownloadItem* operator*() { return iter_->second; }
107
108 MapValueIteratorAdapter& operator++() {
109 ++iter_;
110 return *this;
111 }
112
113 bool operator!=(const MapValueIteratorAdapter& that) const {
114 return iter_ != that.iter_;
115 }
116
117 private:
118 base::hash_map<int64, DownloadItem*>::const_iterator iter_;
119 // Allow copy and assign.
120};
121
[email protected]5948e1a2012-03-10 00:19:18122void EnsureNoPendingDownloadsOnFile(scoped_refptr<DownloadFileManager> dfm,
123 bool* result) {
124 if (dfm->NumberOfActiveDownloads())
125 *result = false;
126 BrowserThread::PostTask(
127 BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure());
128}
129
[email protected]0a5c9112012-03-12 17:49:02130void EnsureNoPendingDownloadJobsOnIO(bool* result) {
[email protected]5948e1a2012-03-10 00:19:18131 scoped_refptr<DownloadFileManager> download_file_manager =
[email protected]ea114722012-03-12 01:11:25132 ResourceDispatcherHostImpl::Get()->download_file_manager();
[email protected]5948e1a2012-03-10 00:19:18133 BrowserThread::PostTask(
134 BrowserThread::FILE, FROM_HERE,
135 base::Bind(&EnsureNoPendingDownloadsOnFile,
136 download_file_manager, result));
137}
138
[email protected]a0ce3282011-08-19 20:49:52139} // namespace
140
[email protected]99907362012-01-11 05:41:40141namespace content {
142
[email protected]5948e1a2012-03-10 00:19:18143bool DownloadManager::EnsureNoPendingDownloadsForTesting() {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145 bool result = true;
146 BrowserThread::PostTask(
147 BrowserThread::IO, FROM_HERE,
[email protected]0a5c9112012-03-12 17:49:02148 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result));
[email protected]5948e1a2012-03-10 00:19:18149 MessageLoop::current()->Run();
150 return result;
151}
152
[email protected]99907362012-01-11 05:41:40153} // namespace content
154
[email protected]b441a8492012-06-06 14:55:57155DownloadManagerImpl::DownloadManagerImpl(net::NetLog* net_log)
156 : shutdown_needed_(false),
157 browser_context_(NULL),
158 file_manager_(NULL),
159 delegate_(NULL),
160 net_log_(net_log) {
initial.commit09911bf2008-07-26 23:55:29161}
162
[email protected]5656f8a2011-11-17 16:12:58163DownloadManagerImpl::~DownloadManagerImpl() {
[email protected]326a6a92010-09-10 20:21:13164 DCHECK(!shutdown_needed_);
initial.commit09911bf2008-07-26 23:55:29165}
166
[email protected]5656f8a2011-11-17 16:12:58167DownloadId DownloadManagerImpl::GetNextId() {
[email protected]491aaa62012-06-07 03:50:18168 DownloadId id;
169 if (delegate_)
170 id = delegate_->GetNextId();
171 if (!id.IsValid()) {
172 static int next_id;
173 id = DownloadId(browser_context_, ++next_id);
174 }
175
176 return id;
[email protected]2909e342011-10-29 00:46:53177}
178
[email protected]fc03de22011-12-06 23:28:12179bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
[email protected]491aaa62012-06-07 03:50:18180 if (!delegate_)
181 return true;
182
[email protected]fc03de22011-12-06 23:28:12183 return delegate_->ShouldOpenDownload(item);
184}
185
186bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
[email protected]491aaa62012-06-07 03:50:18187 if (!delegate_)
188 return false;
189
[email protected]fc03de22011-12-06 23:28:12190 return delegate_->ShouldOpenFileBasedOnExtension(path);
191}
192
[email protected]b441a8492012-06-06 14:55:57193void DownloadManagerImpl::SetDelegate(
194 content::DownloadManagerDelegate* delegate) {
195 delegate_ = delegate;
196}
197
[email protected]b488b5a52012-06-06 17:01:28198content::DownloadManagerDelegate* DownloadManagerImpl::GetDelegate() const {
199 return delegate_;
200}
201
[email protected]5656f8a2011-11-17 16:12:58202void DownloadManagerImpl::Shutdown() {
[email protected]da6e3922010-11-24 21:45:50203 VLOG(20) << __FUNCTION__ << "()"
204 << " shutdown_needed_ = " << shutdown_needed_;
[email protected]326a6a92010-09-10 20:21:13205 if (!shutdown_needed_)
206 return;
207 shutdown_needed_ = false;
initial.commit09911bf2008-07-26 23:55:29208
[email protected]75e51b52012-02-04 16:57:54209 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
[email protected]fb4f8d902011-09-16 06:07:08210 // TODO(benjhayden): Consider clearing observers_.
[email protected]326a6a92010-09-10 20:21:13211
212 if (file_manager_) {
[email protected]ca4b5fa32010-10-09 12:42:18213 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
[email protected]fabf36d22011-10-28 21:50:17214 base::Bind(&DownloadFileManager::OnDownloadManagerShutdown,
215 file_manager_, make_scoped_refptr(this)));
[email protected]326a6a92010-09-10 20:21:13216 }
initial.commit09911bf2008-07-26 23:55:29217
[email protected]f04182f32010-12-10 19:12:07218 AssertContainersConsistent();
219
220 // Go through all downloads in downloads_. Dangerous ones we need to
221 // remove on disk, and in progress ones we need to cancel.
[email protected]57fd1252010-12-23 17:24:09222 for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
[email protected]f04182f32010-12-10 19:12:07223 DownloadItem* download = *it;
224
225 // Save iterator from potential erases in this set done by called code.
226 // Iterators after an erasure point are still valid for lists and
227 // associative containers such as sets.
228 it++;
229
[email protected]c09a8fd2011-11-21 19:54:50230 if (download->GetSafetyState() == DownloadItem::DANGEROUS &&
[email protected]48837962011-04-19 17:03:29231 download->IsPartialDownload()) {
[email protected]f04182f32010-12-10 19:12:07232 // The user hasn't accepted it, so we need to remove it
233 // from the disk. This may or may not result in it being
234 // removed from the DownloadManager queues and deleted
[email protected]fc03de22011-12-06 23:28:12235 // (specifically, DownloadManager::DownloadRemoved only
[email protected]f04182f32010-12-10 19:12:07236 // removes and deletes it if it's known to the history service)
237 // so the only thing we know after calling this function is that
238 // the download was deleted if-and-only-if it was removed
239 // from all queues.
[email protected]303077002011-04-19 23:21:01240 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
[email protected]bf68a00b2011-04-07 17:28:26241 } else if (download->IsPartialDownload()) {
[email protected]93af2272011-09-21 18:29:17242 download->Cancel(false);
[email protected]491aaa62012-06-07 03:50:18243 if (delegate_)
244 delegate_->UpdateItemInPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29245 }
246 }
247
[email protected]f04182f32010-12-10 19:12:07248 // At this point, all dangerous downloads have had their files removed
249 // and all in progress downloads have been cancelled. We can now delete
250 // anything left.
[email protected]9ccbb372008-10-10 18:50:32251
[email protected]5cd11b6e2011-06-10 20:30:59252 // Copy downloads_ to separate container so as not to set off checks
253 // in DownloadItem destruction.
254 DownloadSet downloads_to_delete;
255 downloads_to_delete.swap(downloads_);
256
[email protected]70850c72011-01-11 17:31:27257 active_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59258 history_downloads_.clear();
[email protected]5cd11b6e2011-06-10 20:30:59259 STLDeleteElements(&downloads_to_delete);
initial.commit09911bf2008-07-26 23:55:29260
[email protected]41f558fb2012-01-09 22:59:58261 // We'll have nothing more to report to the observers after this point.
262 observers_.Clear();
263
[email protected]6d0146c2011-08-04 19:13:04264 DCHECK(save_page_downloads_.empty());
265
initial.commit09911bf2008-07-26 23:55:29266 file_manager_ = NULL;
[email protected]b441a8492012-06-06 14:55:57267 if (delegate_)
268 delegate_->Shutdown();
initial.commit09911bf2008-07-26 23:55:29269}
270
[email protected]5656f8a2011-11-17 16:12:58271void DownloadManagerImpl::GetTemporaryDownloads(
[email protected]6d0146c2011-08-04 19:13:04272 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57273 DCHECK(result);
[email protected]6aa4a1c02010-01-15 18:49:58274
[email protected]f04182f32010-12-10 19:12:07275 for (DownloadMap::iterator it = history_downloads_.begin();
276 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50277 if (it->second->IsTemporary() &&
[email protected]3d833de2012-05-30 23:32:06278 (dir_path.empty() ||
279 it->second->GetTargetFilePath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57280 result->push_back(it->second);
[email protected]6aa4a1c02010-01-15 18:49:58281 }
[email protected]6aa4a1c02010-01-15 18:49:58282}
283
[email protected]5656f8a2011-11-17 16:12:58284void DownloadManagerImpl::GetAllDownloads(
[email protected]6d0146c2011-08-04 19:13:04285 const FilePath& dir_path, DownloadVector* result) {
[email protected]82f37b02010-07-29 22:04:57286 DCHECK(result);
[email protected]8ddbd66a2010-05-21 16:38:34287
[email protected]f04182f32010-12-10 19:12:07288 for (DownloadMap::iterator it = history_downloads_.begin();
289 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:50290 if (!it->second->IsTemporary() &&
[email protected]3d833de2012-05-30 23:32:06291 (dir_path.empty() ||
292 it->second->GetTargetFilePath().DirName() == dir_path))
[email protected]82f37b02010-07-29 22:04:57293 result->push_back(it->second);
[email protected]8ddbd66a2010-05-21 16:38:34294 }
[email protected]8ddbd66a2010-05-21 16:38:34295}
296
[email protected]5656f8a2011-11-17 16:12:58297void DownloadManagerImpl::SearchDownloads(const string16& query,
298 DownloadVector* result) {
[email protected]503d03872011-05-06 08:36:26299 string16 query_lower(base::i18n::ToLower(query));
[email protected]d3b12902010-08-16 23:39:42300
[email protected]f04182f32010-12-10 19:12:07301 for (DownloadMap::iterator it = history_downloads_.begin();
302 it != history_downloads_.end(); ++it) {
[email protected]d3b12902010-08-16 23:39:42303 DownloadItem* download_item = it->second;
304
[email protected]c09a8fd2011-11-21 19:54:50305 if (download_item->IsTemporary())
[email protected]d3b12902010-08-16 23:39:42306 continue;
307
308 // Display Incognito downloads only in Incognito window, and vice versa.
309 // The Incognito Downloads page will get the list of non-Incognito downloads
310 // from its parent profile.
[email protected]c09a8fd2011-11-21 19:54:50311 if (browser_context_->IsOffTheRecord() != download_item->IsOtr())
[email protected]d3b12902010-08-16 23:39:42312 continue;
313
314 if (download_item->MatchesQuery(query_lower))
315 result->push_back(download_item);
316 }
[email protected]d3b12902010-08-16 23:39:42317}
318
initial.commit09911bf2008-07-26 23:55:29319// Query the history service for information about all persisted downloads.
[email protected]5656f8a2011-11-17 16:12:58320bool DownloadManagerImpl::Init(content::BrowserContext* browser_context) {
[email protected]6d0c9fb2011-08-22 19:26:03321 DCHECK(browser_context);
initial.commit09911bf2008-07-26 23:55:29322 DCHECK(!shutdown_needed_) << "DownloadManager already initialized.";
323 shutdown_needed_ = true;
324
[email protected]6d0c9fb2011-08-22 19:26:03325 browser_context_ = browser_context;
[email protected]024f2f02010-04-30 22:51:46326
[email protected]ea114722012-03-12 01:11:25327 // In test mode, there may be no ResourceDispatcherHostImpl. In this case
328 // it's safe to avoid setting |file_manager_| because we only call a small
329 // set of functions, none of which need it.
330 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
[email protected]b39e7a88b2012-01-10 21:43:17331 if (rdh) {
332 file_manager_ = rdh->download_file_manager();
333 DCHECK(file_manager_);
334 }
initial.commit09911bf2008-07-26 23:55:29335
initial.commit09911bf2008-07-26 23:55:29336 return true;
337}
338
[email protected]aa9881c2011-08-15 18:01:12339// We have received a message from DownloadFileManager about a new download.
[email protected]5656f8a2011-11-17 16:12:58340void DownloadManagerImpl::StartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]287b86b2011-02-26 00:11:35342
[email protected]491aaa62012-06-07 03:50:18343 if (!delegate_ || delegate_->ShouldStartDownload(download_id))
[email protected]aa9881c2011-08-15 18:01:12344 RestartDownload(download_id);
[email protected]287b86b2011-02-26 00:11:35345}
346
[email protected]5656f8a2011-11-17 16:12:58347void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
[email protected]9fc114672011-06-15 08:17:48348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
349 for (DownloadMap::iterator it = history_downloads_.begin();
350 it != history_downloads_.end(); ++it) {
351 CheckForFileRemoval(it->second);
352 }
353}
354
[email protected]5656f8a2011-11-17 16:12:58355void DownloadManagerImpl::CheckForFileRemoval(DownloadItem* download_item) {
[email protected]9fc114672011-06-15 08:17:48356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
357 if (download_item->IsComplete() &&
[email protected]c09a8fd2011-11-21 19:54:50358 !download_item->GetFileExternallyRemoved()) {
[email protected]9fc114672011-06-15 08:17:48359 BrowserThread::PostTask(
360 BrowserThread::FILE, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58361 base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread,
[email protected]c09a8fd2011-11-21 19:54:50362 this, download_item->GetDbHandle(),
[email protected]fabf36d22011-10-28 21:50:17363 download_item->GetTargetFilePath()));
[email protected]9fc114672011-06-15 08:17:48364 }
365}
366
[email protected]5656f8a2011-11-17 16:12:58367void DownloadManagerImpl::CheckForFileRemovalOnFileThread(
[email protected]9fc114672011-06-15 08:17:48368 int64 db_handle, const FilePath& path) {
369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
370 if (!file_util::PathExists(path)) {
371 BrowserThread::PostTask(
372 BrowserThread::UI, FROM_HERE,
[email protected]5656f8a2011-11-17 16:12:58373 base::Bind(&DownloadManagerImpl::OnFileRemovalDetected,
374 this,
375 db_handle));
[email protected]9fc114672011-06-15 08:17:48376 }
377}
378
[email protected]5656f8a2011-11-17 16:12:58379void DownloadManagerImpl::OnFileRemovalDetected(int64 db_handle) {
[email protected]9fc114672011-06-15 08:17:48380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
381 DownloadMap::iterator it = history_downloads_.find(db_handle);
382 if (it != history_downloads_.end()) {
383 DownloadItem* download_item = it->second;
384 download_item->OnDownloadedFileRemoved();
385 }
386}
387
[email protected]443853c62011-12-22 19:22:41388void DownloadManagerImpl::RestartDownload(int32 download_id) {
[email protected]ca4b5fa32010-10-09 12:42:18389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29390
[email protected]4cd82f72011-05-23 19:15:01391 DownloadItem* download = GetActiveDownloadItem(download_id);
392 if (!download)
393 return;
394
395 VLOG(20) << __FUNCTION__ << "()"
396 << " download = " << download->DebugString(true);
397
[email protected]3d833de2012-05-30 23:32:06398 if (download->GetTargetDisposition() ==
399 DownloadItem::TARGET_DISPOSITION_PROMPT) {
initial.commit09911bf2008-07-26 23:55:29400 // We must ask the user for the place to put the download.
[email protected]a62d42902012-01-24 17:24:38401 WebContents* contents = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:26402
[email protected]491aaa62012-06-07 03:50:18403 if (delegate_) {
404 delegate_->ChooseDownloadPath(contents, download->GetTargetFilePath(),
405 download_id);
406 FOR_EACH_OBSERVER(Observer, observers_,
407 SelectFileDialogDisplayed(this, download_id));
408 } else {
409 FileSelectionCanceled(download_id);
410 }
initial.commit09911bf2008-07-26 23:55:29411 } else {
[email protected]3d833de2012-05-30 23:32:06412 // No prompting for download, just continue with the current target path.
413 OnTargetPathAvailable(download);
initial.commit09911bf2008-07-26 23:55:29414 }
415}
416
[email protected]37757c62011-12-20 20:07:12417content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
[email protected]5656f8a2011-11-17 16:12:58418 return browser_context_;
419}
420
421FilePath DownloadManagerImpl::LastDownloadPath() {
422 return last_download_path_;
423}
424
[email protected]ef17c9a2012-02-09 05:08:09425net::BoundNetLog DownloadManagerImpl::CreateDownloadItem(
[email protected]594e66fe2011-10-25 22:49:41426 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
[email protected]c2e76012010-12-23 21:10:29427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
428
[email protected]ef17c9a2012-02-09 05:08:09429 net::BoundNetLog bound_net_log =
430 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]491aaa62012-06-07 03:50:18431 info->download_id = GetNextId();
[email protected]c09a8fd2011-11-21 19:54:50432 DownloadItem* download = new DownloadItemImpl(
[email protected]ae77da82011-11-01 19:17:29433 this, *info, new DownloadRequestHandle(request_handle),
[email protected]ef17c9a2012-02-09 05:08:09434 browser_context_->IsOffTheRecord(), bound_net_log);
[email protected]2909e342011-10-29 00:46:53435 int32 download_id = info->download_id.local();
[email protected]d8472d92011-08-26 20:15:20436
[email protected]0634626a2012-05-03 19:04:26437 DCHECK(!ContainsKey(active_downloads_, download_id));
[email protected]c2e76012010-12-23 21:10:29438 downloads_.insert(download);
[email protected]4cd82f72011-05-23 19:15:01439 active_downloads_[download_id] = download;
[email protected]ef17c9a2012-02-09 05:08:09440
441 return bound_net_log;
[email protected]c2e76012010-12-23 21:10:29442}
443
[email protected]fc03de22011-12-06 23:28:12444DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
445 const FilePath& main_file_path,
446 const GURL& page_url,
447 bool is_otr,
[email protected]6474b112012-05-04 19:35:27448 const std::string& mime_type,
[email protected]fc03de22011-12-06 23:28:12449 DownloadItem::Observer* observer) {
[email protected]ef17c9a2012-02-09 05:08:09450 net::BoundNetLog bound_net_log =
451 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12452 DownloadItem* download = new DownloadItemImpl(
[email protected]6474b112012-05-04 19:35:27453 this,
454 main_file_path,
455 page_url,
456 is_otr,
457 GetNextId(),
458 mime_type,
459 bound_net_log);
[email protected]fc03de22011-12-06 23:28:12460
461 download->AddObserver(observer);
462
463 DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
464 downloads_.insert(download);
465 save_page_downloads_[download->GetId()] = download;
466
467 // Will notify the observer in the callback.
[email protected]491aaa62012-06-07 03:50:18468 if (delegate_)
469 delegate_->AddItemToPersistentStore(download);
[email protected]fc03de22011-12-06 23:28:12470
471 return download;
472}
473
[email protected]3d833de2012-05-30 23:32:06474// The target path for the download item is now valid. We proceed with the
475// determination of an intermediate path.
476void DownloadManagerImpl::OnTargetPathAvailable(DownloadItem* download) {
[email protected]ca4b5fa32010-10-09 12:42:18477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01478 DCHECK(download);
[email protected]aa033af2010-07-27 18:16:39479
[email protected]c09a8fd2011-11-21 19:54:50480 int32 download_id = download->GetId();
initial.commit09911bf2008-07-26 23:55:29481
[email protected]70850c72011-01-11 17:31:27482 DCHECK(ContainsKey(downloads_, download));
[email protected]4cd82f72011-05-23 19:15:01483 DCHECK(ContainsKey(active_downloads_, download_id));
[email protected]70850c72011-01-11 17:31:27484
[email protected]4cd82f72011-05-23 19:15:01485 VLOG(20) << __FUNCTION__ << "()"
486 << " download = " << download->DebugString(true);
487
[email protected]adb2f3d12011-01-23 16:24:54488 // Rename to intermediate name.
[email protected]3d833de2012-05-30 23:32:06489 // TODO(asanka): Skip this rename if download->AllDataSaved() is true. This
490 // avoids a spurious rename when we can just rename to the final
491 // filename. Unnecessary renames may cause bugs like
492 // http://crbug.com/74187.
493 bool ok_to_overwrite = true;
[email protected]491aaa62012-06-07 03:50:18494 FilePath intermediate_path;
495 if (delegate_) {
496 intermediate_path =
497 delegate_->GetIntermediatePath(*download, &ok_to_overwrite);
498 } else {
499 intermediate_path = download->GetTargetFilePath();
500 }
[email protected]3d833de2012-05-30 23:32:06501 // We want the intermediate and target paths to refer to the same directory so
502 // that they are both on the same device and subject to same
503 // space/permission/availability constraints.
504 DCHECK(intermediate_path.DirName() ==
505 download->GetTargetFilePath().DirName());
506 download->OnIntermediatePathDetermined(file_manager_, intermediate_path,
507 ok_to_overwrite);
initial.commit09911bf2008-07-26 23:55:29508}
509
[email protected]443853c62011-12-22 19:22:41510void DownloadManagerImpl::UpdateDownload(int32 download_id,
511 int64 bytes_so_far,
512 int64 bytes_per_sec,
[email protected]0afff032012-01-06 20:55:00513 const std::string& hash_state) {
[email protected]70850c72011-01-11 17:31:27514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
515 DownloadMap::iterator it = active_downloads_.find(download_id);
516 if (it != active_downloads_.end()) {
initial.commit09911bf2008-07-26 23:55:29517 DownloadItem* download = it->second;
[email protected]bf68a00b2011-04-07 17:28:26518 if (download->IsInProgress()) {
[email protected]443853c62011-12-22 19:22:41519 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
[email protected]491aaa62012-06-07 03:50:18520 if (delegate_)
521 delegate_->UpdateItemInPersistentStore(download);
[email protected]70850c72011-01-11 17:31:27522 }
initial.commit09911bf2008-07-26 23:55:29523 }
524}
525
[email protected]5656f8a2011-11-17 16:12:58526void DownloadManagerImpl::OnResponseCompleted(int32 download_id,
527 int64 size,
528 const std::string& hash) {
[email protected]33c6d3f12011-09-04 00:00:54529 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]da6e3922010-11-24 21:45:50530 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
531 << " size = " << size;
[email protected]9d7ef802011-02-25 19:03:35532 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9ccbb372008-10-10 18:50:32533
[email protected]c4f02c42011-01-24 21:55:06534 // If it's not in active_downloads_, that means it was cancelled; just
535 // ignore the notification.
536 if (active_downloads_.count(download_id) == 0)
537 return;
538
[email protected]adb2f3d12011-01-23 16:24:54539 DownloadItem* download = active_downloads_[download_id];
[email protected]ac4af82f2011-11-10 19:09:37540 download->OnAllDataSaved(size, hash);
[email protected]da4cd4262012-05-18 20:42:35541 MaybeCompleteDownload(download);
[email protected]adb2f3d12011-01-23 16:24:54542}
[email protected]9ccbb372008-10-10 18:50:32543
[email protected]fc03de22011-12-06 23:28:12544void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
[email protected]c09a8fd2011-11-21 19:54:50545 if (download->GetState() == DownloadItem::REMOVING) {
[email protected]0634626a2012-05-03 19:04:26546 DCHECK(!ContainsKey(downloads_, download));
547 DCHECK(!ContainsKey(active_downloads_, download->GetId()));
[email protected]0634626a2012-05-03 19:04:26548 DCHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17549 return;
550 }
551
552 // Should be in downloads_ if we're not REMOVING.
553 CHECK(ContainsKey(downloads_, download));
554
555 // Check history_downloads_ consistency.
[email protected]5009b7a2012-02-21 18:47:03556 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50557 CHECK(ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]7d413112011-06-16 18:50:17558 } else {
[email protected]fc03de22011-12-06 23:28:12559 for (DownloadMap::const_iterator it = history_downloads_.begin();
[email protected]7d413112011-06-16 18:50:17560 it != history_downloads_.end(); ++it) {
[email protected]0634626a2012-05-03 19:04:26561 DCHECK(it->second != download);
[email protected]7d413112011-06-16 18:50:17562 }
563 }
564
[email protected]c09a8fd2011-11-21 19:54:50565 int64 state = download->GetState();
[email protected]61b75a52011-08-29 16:34:34566 base::debug::Alias(&state);
[email protected]c09a8fd2011-11-21 19:54:50567 if (ContainsKey(active_downloads_, download->GetId())) {
[email protected]5009b7a2012-02-21 18:47:03568 if (download->IsPersisted())
[email protected]c09a8fd2011-11-21 19:54:50569 CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState());
570 if (DownloadItem::IN_PROGRESS != download->GetState())
571 CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle());
[email protected]f9a2997f2011-09-23 16:54:07572 }
[email protected]c09a8fd2011-11-21 19:54:50573 if (DownloadItem::IN_PROGRESS == download->GetState())
574 CHECK(ContainsKey(active_downloads_, download->GetId()));
[email protected]5cd11b6e2011-06-10 20:30:59575}
576
[email protected]5656f8a2011-11-17 16:12:58577bool DownloadManagerImpl::IsDownloadReadyForCompletion(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54578 // If we don't have all the data, the download is not ready for
579 // completion.
[email protected]c09a8fd2011-11-21 19:54:50580 if (!download->AllDataSaved())
[email protected]adb2f3d12011-01-23 16:24:54581 return false;
[email protected]6a7fb042010-02-01 16:30:47582
[email protected]9d7ef802011-02-25 19:03:35583 // If the download is dangerous, but not yet validated, it's not ready for
584 // completion.
[email protected]c09a8fd2011-11-21 19:54:50585 if (download->GetSafetyState() == DownloadItem::DANGEROUS)
[email protected]9d7ef802011-02-25 19:03:35586 return false;
587
[email protected]adb2f3d12011-01-23 16:24:54588 // If the download isn't active (e.g. has been cancelled) it's not
589 // ready for completion.
[email protected]c09a8fd2011-11-21 19:54:50590 if (active_downloads_.count(download->GetId()) == 0)
[email protected]adb2f3d12011-01-23 16:24:54591 return false;
592
593 // If the download hasn't been inserted into the history system
594 // (which occurs strictly after file name determination, intermediate
595 // file rename, and UI display) then it's not ready for completion.
[email protected]5009b7a2012-02-21 18:47:03596 if (!download->IsPersisted())
[email protected]7054b592011-06-22 14:46:42597 return false;
598
599 return true;
[email protected]adb2f3d12011-01-23 16:24:54600}
601
[email protected]6474b112012-05-04 19:35:27602// When SavePackage downloads MHTML to GData (see
603// SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
604// does for non-SavePackage downloads, but SavePackage downloads never satisfy
605// IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
606// DownloadItem::UpdateObservers() when the upload completes so that SavePackage
607// notices that the upload has completed and runs its normal Finish() pathway.
608// MaybeCompleteDownload() is never the mechanism by which SavePackage completes
609// downloads. SavePackage always uses its own Finish() to mark downloads
610// complete.
611
[email protected]5656f8a2011-11-17 16:12:58612void DownloadManagerImpl::MaybeCompleteDownload(DownloadItem* download) {
[email protected]adb2f3d12011-01-23 16:24:54613 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
614 VLOG(20) << __FUNCTION__ << "()" << " download = "
615 << download->DebugString(false);
616
617 if (!IsDownloadReadyForCompletion(download))
[email protected]9ccbb372008-10-10 18:50:32618 return;
[email protected]9ccbb372008-10-10 18:50:32619
[email protected]adb2f3d12011-01-23 16:24:54620 // TODO(rdsmith): DCHECK that we only pass through this point
621 // once per download. The natural way to do this is by a state
622 // transition on the DownloadItem.
[email protected]594cd7d2010-07-21 03:23:56623
[email protected]adb2f3d12011-01-23 16:24:54624 // Confirm we're in the proper set of states to be here;
[email protected]550520f2012-05-14 20:58:48625 // have all data, have a history handle, (validated or safe).
626 DCHECK(download->IsInProgress());
[email protected]c09a8fd2011-11-21 19:54:50627 DCHECK_NE(DownloadItem::DANGEROUS, download->GetSafetyState());
[email protected]c09a8fd2011-11-21 19:54:50628 DCHECK(download->AllDataSaved());
[email protected]5009b7a2012-02-21 18:47:03629 DCHECK(download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50630 DCHECK_EQ(1u, history_downloads_.count(download->GetDbHandle()));
[email protected]adb2f3d12011-01-23 16:24:54631
[email protected]da4cd4262012-05-18 20:42:35632 // Give the delegate a chance to override. It's ok to keep re-setting the
633 // delegate's |complete_callback| cb as long as there isn't another call-point
634 // trying to set it to a different cb. TODO(benjhayden): Change the callback
635 // to point directly to the item instead of |this| when DownloadItem supports
636 // weak-ptrs.
[email protected]491aaa62012-06-07 03:50:18637 if (delegate_ && !delegate_->ShouldCompleteDownload(download, base::Bind(
[email protected]da4cd4262012-05-18 20:42:35638 &DownloadManagerImpl::MaybeCompleteDownloadById,
639 this, download->GetId())))
[email protected]c2918652011-11-01 18:50:23640 return;
641
[email protected]adb2f3d12011-01-23 16:24:54642 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
643 << download->DebugString(false);
644
[email protected]491aaa62012-06-07 03:50:18645 if (delegate_)
646 delegate_->UpdateItemInPersistentStore(download);
[email protected]48837962011-04-19 17:03:29647 download->OnDownloadCompleting(file_manager_);
[email protected]9ccbb372008-10-10 18:50:32648}
649
[email protected]da4cd4262012-05-18 20:42:35650void DownloadManagerImpl::MaybeCompleteDownloadById(int download_id) {
651 DownloadItem* download_item = GetActiveDownload(download_id);
652 if (download_item != NULL)
653 MaybeCompleteDownload(download_item);
654}
655
[email protected]fc03de22011-12-06 23:28:12656void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
[email protected]70850c72011-01-11 17:31:27657 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cc3c7c092011-05-09 18:40:21658 DCHECK(download);
[email protected]491aaa62012-06-07 03:50:18659 if (delegate_)
660 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::CancelDownload(int32 download_id) {
[email protected]93af2272011-09-21 18:29:17666 DownloadItem* download = GetActiveDownload(download_id);
667 // A cancel at the right time could remove the download from the
668 // |active_downloads_| map before we get here.
669 if (!download)
670 return;
671
672 download->Cancel(true);
673}
674
[email protected]fc03de22011-12-06 23:28:12675void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
[email protected]d8472d92011-08-26 20:15:20676 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d8472d92011-08-26 20:15:20677
678 VLOG(20) << __FUNCTION__ << "()"
[email protected]da6e3922010-11-24 21:45:50679 << " download = " << download->DebugString(true);
680
[email protected]93af2272011-09-21 18:29:17681 RemoveFromActiveList(download);
[email protected]47a881b2011-08-29 22:59:21682 // This function is called from the DownloadItem, so DI state
683 // should already have been updated.
[email protected]fc03de22011-12-06 23:28:12684 AssertStateConsistent(download);
initial.commit09911bf2008-07-26 23:55:29685
[email protected]15d90ba2011-11-03 03:41:55686 if (file_manager_)
687 download->OffThreadCancel(file_manager_);
initial.commit09911bf2008-07-26 23:55:29688}
689
[email protected]bf3b08a2012-03-08 01:52:34690void DownloadManagerImpl::OnDownloadInterrupted(
691 int32 download_id,
692 int64 size,
693 const std::string& hash_state,
694 content::DownloadInterruptReason reason) {
[email protected]47a881b2011-08-29 22:59:21695 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
696
697 DownloadItem* download = GetActiveDownload(download_id);
698 if (!download)
699 return;
700
[email protected]be76b7e2011-10-13 12:57:57701 VLOG(20) << __FUNCTION__ << "()"
702 << " reason " << InterruptReasonDebugString(reason)
[email protected]c09a8fd2011-11-21 19:54:50703 << " at offset " << download->GetReceivedBytes()
[email protected]47a881b2011-08-29 22:59:21704 << " size = " << size
705 << " download = " << download->DebugString(true);
706
[email protected]93af2272011-09-21 18:29:17707 RemoveFromActiveList(download);
[email protected]443853c62011-12-22 19:22:41708 download->Interrupted(size, hash_state, reason);
[email protected]93af2272011-09-21 18:29:17709 download->OffThreadCancel(file_manager_);
[email protected]47a881b2011-08-29 22:59:21710}
711
[email protected]5656f8a2011-11-17 16:12:58712DownloadItem* DownloadManagerImpl::GetActiveDownload(int32 download_id) {
[email protected]bf68a00b2011-04-07 17:28:26713 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
714 DownloadMap::iterator it = active_downloads_.find(download_id);
[email protected]bf68a00b2011-04-07 17:28:26715 if (it == active_downloads_.end())
[email protected]47a881b2011-08-29 22:59:21716 return NULL;
[email protected]bf68a00b2011-04-07 17:28:26717
718 DownloadItem* download = it->second;
719
[email protected]47a881b2011-08-29 22:59:21720 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50721 DCHECK_EQ(download_id, download->GetId());
[email protected]4cd82f72011-05-23 19:15:01722
[email protected]47a881b2011-08-29 22:59:21723 return download;
724}
[email protected]54610672011-07-18 18:24:43725
[email protected]5656f8a2011-11-17 16:12:58726void DownloadManagerImpl::RemoveFromActiveList(DownloadItem* download) {
[email protected]93af2272011-09-21 18:29:17727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
728 DCHECK(download);
729
730 // Clean up will happen when the history system create callback runs if we
731 // don't have a valid db_handle yet.
[email protected]5009b7a2012-02-21 18:47:03732 if (download->IsPersisted()) {
[email protected]c09a8fd2011-11-21 19:54:50733 active_downloads_.erase(download->GetId());
[email protected]491aaa62012-06-07 03:50:18734 if (delegate_)
735 delegate_->UpdateItemInPersistentStore(download);
[email protected]93af2272011-09-21 18:29:17736 }
737}
738
[email protected]fd3a82832012-01-19 20:35:12739bool DownloadManagerImpl::GenerateFileHash() {
[email protected]491aaa62012-06-07 03:50:18740 return delegate_ && delegate_->GenerateFileHash();
[email protected]fd3a82832012-01-19 20:35:12741}
742
[email protected]5656f8a2011-11-17 16:12:58743int DownloadManagerImpl::RemoveDownloadItems(
[email protected]6d0146c2011-08-04 19:13:04744 const DownloadVector& pending_deletes) {
745 if (pending_deletes.empty())
746 return 0;
747
748 // Delete from internal maps.
749 for (DownloadVector::const_iterator it = pending_deletes.begin();
750 it != pending_deletes.end();
751 ++it) {
752 DownloadItem* download = *it;
753 DCHECK(download);
[email protected]c09a8fd2011-11-21 19:54:50754 history_downloads_.erase(download->GetDbHandle());
755 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:04756 downloads_.erase(download);
757 }
758
759 // Tell observers to refresh their views.
760 NotifyModelChanged();
761
762 // Delete the download items themselves.
763 const int num_deleted = static_cast<int>(pending_deletes.size());
764 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
765 return num_deleted;
766}
767
[email protected]fc03de22011-12-06 23:28:12768void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
769 if (history_downloads_.find(download->GetDbHandle()) ==
770 history_downloads_.end())
[email protected]93af2272011-09-21 18:29:17771 return;
772
773 // Make history update.
[email protected]491aaa62012-06-07 03:50:18774 if (delegate_)
775 delegate_->RemoveItemFromPersistentStore(download);
initial.commit09911bf2008-07-26 23:55:29776
777 // Remove from our tables and delete.
[email protected]6d0146c2011-08-04 19:13:04778 int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
[email protected]f04182f32010-12-10 19:12:07779 DCHECK_EQ(1, downloads_count);
initial.commit09911bf2008-07-26 23:55:29780}
781
[email protected]fd3a82832012-01-19 20:35:12782int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
783 base::Time remove_end) {
[email protected]491aaa62012-06-07 03:50:18784 if (delegate_)
785 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end);
initial.commit09911bf2008-07-26 23:55:29786
[email protected]a312a442010-12-15 23:40:33787 // All downloads visible to the user will be in the history,
788 // so scan that map.
[email protected]6d0146c2011-08-04 19:13:04789 DownloadVector pending_deletes;
790 for (DownloadMap::const_iterator it = history_downloads_.begin();
791 it != history_downloads_.end();
792 ++it) {
initial.commit09911bf2008-07-26 23:55:29793 DownloadItem* download = it->second;
[email protected]c09a8fd2011-11-21 19:54:50794 if (download->GetStartTime() >= remove_begin &&
795 (remove_end.is_null() || download->GetStartTime() < remove_end) &&
[email protected]6d0146c2011-08-04 19:13:04796 (download->IsComplete() || download->IsCancelled())) {
[email protected]fc03de22011-12-06 23:28:12797 AssertStateConsistent(download);
[email protected]78b8fcc92009-03-31 17:36:28798 pending_deletes.push_back(download);
initial.commit09911bf2008-07-26 23:55:29799 }
initial.commit09911bf2008-07-26 23:55:29800 }
[email protected]6d0146c2011-08-04 19:13:04801 return RemoveDownloadItems(pending_deletes);
initial.commit09911bf2008-07-26 23:55:29802}
803
[email protected]fd3a82832012-01-19 20:35:12804int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
[email protected]e93d2822009-01-30 05:59:59805 return RemoveDownloadsBetween(remove_begin, base::Time());
initial.commit09911bf2008-07-26 23:55:29806}
807
[email protected]5656f8a2011-11-17 16:12:58808int DownloadManagerImpl::RemoveAllDownloads() {
[email protected]da4a5582011-10-17 19:08:06809 download_stats::RecordClearAllSize(history_downloads_.size());
[email protected]d41355e6f2009-04-07 21:21:12810 // The null times make the date range unbounded.
811 return RemoveDownloadsBetween(base::Time(), base::Time());
812}
813
[email protected]0d4e30c2012-01-28 00:47:53814void DownloadManagerImpl::DownloadUrl(
[email protected]c5a5c0842012-05-04 20:05:14815 scoped_ptr<content::DownloadUrlParameters> params) {
816 if (params->post_id() >= 0) {
817 // Check this here so that the traceback is more useful.
818 DCHECK(params->prefer_cache());
819 DCHECK(params->method() == "POST");
820 }
821 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
822 &BeginDownload, base::Owned(params.release())));
initial.commit09911bf2008-07-26 23:55:29823}
824
[email protected]5656f8a2011-11-17 16:12:58825void DownloadManagerImpl::AddObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29826 observers_.AddObserver(observer);
[email protected]a1e41e72012-02-22 17:41:25827 // TODO: It is the responsibility of the observers to query the
828 // DownloadManager. Remove the following call from here and update all
829 // observers.
[email protected]75e51b52012-02-04 16:57:54830 observer->ModelChanged(this);
initial.commit09911bf2008-07-26 23:55:29831}
832
[email protected]5656f8a2011-11-17 16:12:58833void DownloadManagerImpl::RemoveObserver(Observer* observer) {
initial.commit09911bf2008-07-26 23:55:29834 observers_.RemoveObserver(observer);
835}
836
[email protected]84d57412012-03-03 08:59:55837void DownloadManagerImpl::FileSelected(const FilePath& path,
838 int32 download_id) {
[email protected]4cd82f72011-05-23 19:15:01839 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d833de2012-05-30 23:32:06840 DCHECK(!path.empty());
[email protected]4cd82f72011-05-23 19:15:01841
[email protected]4cd82f72011-05-23 19:15:01842 DownloadItem* download = GetActiveDownloadItem(download_id);
843 if (!download)
844 return;
845 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
[email protected]3d833de2012-05-30 23:32:06846 << " download = " << download->DebugString(true);
[email protected]4cd82f72011-05-23 19:15:01847
[email protected]3d833de2012-05-30 23:32:06848 // Retain the last directory. Exclude temporary downloads since the path
849 // likely points at the location of a temporary file.
850 if (!download->IsTemporary())
[email protected]7ae7c2cb2009-01-06 23:31:41851 last_download_path_ = path.DirName();
[email protected]287b86b2011-02-26 00:11:35852
[email protected]4cd82f72011-05-23 19:15:01853 // Make sure the initial file name is set only once.
[email protected]3d833de2012-05-30 23:32:06854 download->OnTargetPathSelected(path);
855 OnTargetPathAvailable(download);
initial.commit09911bf2008-07-26 23:55:29856}
857
[email protected]84d57412012-03-03 08:59:55858void DownloadManagerImpl::FileSelectionCanceled(int32 download_id) {
initial.commit09911bf2008-07-26 23:55:29859 // The user didn't pick a place to save the file, so need to cancel the
860 // download that's already in progress to the temporary location.
[email protected]4cd82f72011-05-23 19:15:01861 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4cd82f72011-05-23 19:15:01862
863 DownloadItem* download = GetActiveDownloadItem(download_id);
864 if (!download)
865 return;
866
867 VLOG(20) << __FUNCTION__ << "()"
868 << " download = " << download->DebugString(true);
869
[email protected]8f8bc112012-02-22 12:36:31870 download->Cancel(true);
[email protected]4cd82f72011-05-23 19:15:01871}
872
initial.commit09911bf2008-07-26 23:55:29873// Operations posted to us from the history service ----------------------------
874
875// The history service has retrieved all download entries. 'entries' contains
[email protected]bb1a4212011-08-22 22:38:25876// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
[email protected]5656f8a2011-11-17 16:12:58877void DownloadManagerImpl::OnPersistentStoreQueryComplete(
[email protected]bb1a4212011-08-22 22:38:25878 std::vector<DownloadPersistentStoreInfo>* entries) {
initial.commit09911bf2008-07-26 23:55:29879 for (size_t i = 0; i < entries->size(); ++i) {
[email protected]deb40832012-02-23 15:41:37880 int64 db_handle = entries->at(i).db_handle;
881 base::debug::Alias(&db_handle);
[email protected]0634626a2012-05-03 19:04:26882 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]deb40832012-02-23 15:41:37883
[email protected]ef17c9a2012-02-09 05:08:09884 net::BoundNetLog bound_net_log =
885 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
[email protected]fc03de22011-12-06 23:28:12886 DownloadItem* download = new DownloadItemImpl(
[email protected]ef17c9a2012-02-09 05:08:09887 this, GetNextId(), entries->at(i), bound_net_log);
[email protected]f04182f32010-12-10 19:12:07888 downloads_.insert(download);
[email protected]c09a8fd2011-11-21 19:54:50889 history_downloads_[download->GetDbHandle()] = download;
[email protected]da6e3922010-11-24 21:45:50890 VLOG(20) << __FUNCTION__ << "()" << i << ">"
891 << " download = " << download->DebugString(true);
initial.commit09911bf2008-07-26 23:55:29892 }
[email protected]b0ab1d42010-02-24 19:29:28893 NotifyModelChanged();
[email protected]9fc114672011-06-15 08:17:48894 CheckForHistoryFilesRemoval();
initial.commit09911bf2008-07-26 23:55:29895}
896
[email protected]5656f8a2011-11-17 16:12:58897void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItem* download,
898 int64 db_handle) {
[email protected]70850c72011-01-11 17:31:27899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]0634626a2012-05-03 19:04:26900 DCHECK_NE(DownloadItem::kUninitializedHandle, db_handle);
[email protected]1e9fe7ff2011-06-24 17:37:33901
[email protected]da4a5582011-10-17 19:08:06902 download_stats::RecordHistorySize(history_downloads_.size());
903
[email protected]5009b7a2012-02-21 18:47:03904 DCHECK(!download->IsPersisted());
[email protected]c09a8fd2011-11-21 19:54:50905 download->SetDbHandle(db_handle);
[email protected]5009b7a2012-02-21 18:47:03906 download->SetIsPersisted();
[email protected]5bcd73eb2011-03-23 21:14:02907
[email protected]0634626a2012-05-03 19:04:26908 DCHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
[email protected]c09a8fd2011-11-21 19:54:50909 history_downloads_[download->GetDbHandle()] = download;
[email protected]6d0146c2011-08-04 19:13:04910
911 // Show in the appropriate browser UI.
912 // This includes buttons to save or cancel, for a dangerous download.
913 ShowDownloadInBrowser(download);
914
915 // Inform interested objects about the new download.
916 NotifyModelChanged();
[email protected]f9a45b02011-06-30 23:49:19917}
918
[email protected]2588ea9d2011-08-22 20:59:53919
[email protected]5656f8a2011-11-17 16:12:58920void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id,
921 int64 db_handle) {
[email protected]2588ea9d2011-08-22 20:59:53922 if (save_page_downloads_.count(download_id)) {
923 OnSavePageItemAddedToPersistentStore(download_id, db_handle);
924 } else if (active_downloads_.count(download_id)) {
925 OnDownloadItemAddedToPersistentStore(download_id, db_handle);
926 }
927 // It's valid that we don't find a matching item, i.e. on shutdown.
928}
929
[email protected]f9a45b02011-06-30 23:49:19930// Once the new DownloadItem's creation info has been committed to the history
931// service, we associate the DownloadItem with the db handle, update our
932// 'history_downloads_' map and inform observers.
[email protected]5656f8a2011-11-17 16:12:58933void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore(
934 int32 download_id, int64 db_handle) {
[email protected]f9a45b02011-06-30 23:49:19935 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]19420cc2011-07-18 17:43:45936 DownloadItem* download = GetActiveDownloadItem(download_id);
[email protected]93af2272011-09-21 18:29:17937 if (!download)
[email protected]19420cc2011-07-18 17:43:45938 return;
[email protected]54610672011-07-18 18:24:43939
940 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
941 << " download_id = " << download_id
942 << " download = " << download->DebugString(true);
[email protected]f9a45b02011-06-30 23:49:19943
[email protected]e5107ce2011-09-19 20:36:13944 int32 matching_item_download_id
945 = (ContainsKey(history_downloads_, db_handle) ?
[email protected]c09a8fd2011-11-21 19:54:50946 history_downloads_[db_handle]->GetId() : 0);
[email protected]e5107ce2011-09-19 20:36:13947 base::debug::Alias(&matching_item_download_id);
948
[email protected]0634626a2012-05-03 19:04:26949 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:20950
[email protected]f9a45b02011-06-30 23:49:19951 AddDownloadItemToHistory(download, db_handle);
initial.commit09911bf2008-07-26 23:55:29952
[email protected]93af2272011-09-21 18:29:17953 // If the download is still in progress, try to complete it.
954 //
955 // Otherwise, download has been cancelled or interrupted before we've
956 // received the DB handle. We post one final message to the history
957 // service so that it can be properly in sync with the DownloadItem's
958 // completion status, and also inform any observers so that they get
959 // more than just the start notification.
960 if (download->IsInProgress()) {
961 MaybeCompleteDownload(download);
962 } else {
[email protected]0634626a2012-05-03 19:04:26963 DCHECK(download->IsCancelled());
[email protected]93af2272011-09-21 18:29:17964 active_downloads_.erase(download_id);
[email protected]491aaa62012-06-07 03:50:18965 if (delegate_)
966 delegate_->UpdateItemInPersistentStore(download);
[email protected]93af2272011-09-21 18:29:17967 download->UpdateObservers();
968 }
initial.commit09911bf2008-07-26 23:55:29969}
970
[email protected]5656f8a2011-11-17 16:12:58971void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItem* download) {
[email protected]a29e4f22012-04-12 21:22:03972 // The 'contents' may no longer exist if the user closed the contents before
973 // we get this start completion event.
[email protected]a62d42902012-01-24 17:24:38974 WebContents* content = download->GetWebContents();
[email protected]99cb7f82011-07-28 17:27:26975
976 // If the contents no longer exists, we ask the embedder to suggest another
[email protected]a29e4f22012-04-12 21:22:03977 // contents.
[email protected]491aaa62012-06-07 03:50:18978 if (!content && delegate_)
[email protected]ef9572e2012-01-04 22:14:12979 content = delegate_->GetAlternativeWebContentsToNotifyForDownload();
[email protected]5e595482009-05-06 20:16:53980
[email protected]0bfbf882011-12-22 18:19:27981 if (content && content->GetDelegate())
982 content->GetDelegate()->OnStartDownload(content, download);
[email protected]5e595482009-05-06 20:16:53983}
984
[email protected]5656f8a2011-11-17 16:12:58985int DownloadManagerImpl::InProgressCount() const {
[email protected]550520f2012-05-14 20:58:48986 // Don't use active_downloads_.count() because Cancel() leaves items in
987 // active_downloads_ if they haven't made it into the persistent store yet.
[email protected]007e7412012-03-13 20:10:56988 // Need to actually look at each item's state.
989 int count = 0;
[email protected]550520f2012-05-14 20:58:48990 for (DownloadMap::const_iterator it = active_downloads_.begin();
991 it != active_downloads_.end(); ++it) {
[email protected]007e7412012-03-13 20:10:56992 DownloadItem* item = it->second;
993 if (item->IsInProgress())
994 ++count;
995 }
996 return count;
[email protected]5656f8a2011-11-17 16:12:58997}
998
[email protected]6cade212008-12-03 00:32:22999// Clears the last download path, used to initialize "save as" dialogs.
[email protected]5656f8a2011-11-17 16:12:581000void DownloadManagerImpl::ClearLastDownloadPath() {
[email protected]7ae7c2cb2009-01-06 23:31:411001 last_download_path_ = FilePath();
[email protected]eea46622009-07-15 20:49:381002}
[email protected]b0ab1d42010-02-24 19:29:281003
[email protected]5656f8a2011-11-17 16:12:581004void DownloadManagerImpl::NotifyModelChanged() {
[email protected]75e51b52012-02-04 16:57:541005 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged(this));
[email protected]b0ab1d42010-02-24 19:29:281006}
1007
[email protected]5656f8a2011-11-17 16:12:581008DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
[email protected]4cd82f72011-05-23 19:15:011009 // The |history_downloads_| map is indexed by the download's db_handle,
1010 // not its id, so we have to iterate.
[email protected]f04182f32010-12-10 19:12:071011 for (DownloadMap::iterator it = history_downloads_.begin();
1012 it != history_downloads_.end(); ++it) {
[email protected]2e030682010-07-23 19:45:361013 DownloadItem* item = it->second;
[email protected]c09a8fd2011-11-21 19:54:501014 if (item->GetId() == download_id)
[email protected]2e030682010-07-23 19:45:361015 return item;
1016 }
1017 return NULL;
1018}
1019
[email protected]5656f8a2011-11-17 16:12:581020DownloadItem* DownloadManagerImpl::GetActiveDownloadItem(int download_id) {
[email protected]5d3e83642011-12-16 01:14:361021 if (ContainsKey(active_downloads_, download_id))
1022 return active_downloads_[download_id];
1023 return NULL;
[email protected]4cd82f72011-05-23 19:15:011024}
1025
[email protected]57fd1252010-12-23 17:24:091026// Confirm that everything in all maps is also in |downloads_|, and that
1027// everything in |downloads_| is also in some other map.
[email protected]5656f8a2011-11-17 16:12:581028void DownloadManagerImpl::AssertContainersConsistent() const {
[email protected]f04182f32010-12-10 19:12:071029#if !defined(NDEBUG)
[email protected]57fd1252010-12-23 17:24:091030 // Turn everything into sets.
[email protected]6d0146c2011-08-04 19:13:041031 const DownloadMap* input_maps[] = {&active_downloads_,
1032 &history_downloads_,
1033 &save_page_downloads_};
1034 DownloadSet active_set, history_set, save_page_set;
1035 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
1036 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
[email protected]57fd1252010-12-23 17:24:091037 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
1038 for (DownloadMap::const_iterator it = input_maps[i]->begin();
[email protected]6d0146c2011-08-04 19:13:041039 it != input_maps[i]->end(); ++it) {
1040 all_sets[i]->insert(&*it->second);
[email protected]f04182f32010-12-10 19:12:071041 }
1042 }
[email protected]57fd1252010-12-23 17:24:091043
1044 // Check if each set is fully present in downloads, and create a union.
[email protected]57fd1252010-12-23 17:24:091045 DownloadSet downloads_union;
1046 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
1047 DownloadSet remainder;
1048 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
1049 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
1050 downloads_.begin(), downloads_.end(),
1051 insert_it);
1052 DCHECK(remainder.empty());
1053 std::insert_iterator<DownloadSet>
1054 insert_union(downloads_union, downloads_union.end());
1055 std::set_union(downloads_union.begin(), downloads_union.end(),
1056 all_sets[i]->begin(), all_sets[i]->end(),
1057 insert_union);
1058 }
1059
1060 // Is everything in downloads_ present in one of the other sets?
1061 DownloadSet remainder;
1062 std::insert_iterator<DownloadSet>
1063 insert_remainder(remainder, remainder.begin());
1064 std::set_difference(downloads_.begin(), downloads_.end(),
1065 downloads_union.begin(), downloads_union.end(),
1066 insert_remainder);
1067 DCHECK(remainder.empty());
[email protected]f04182f32010-12-10 19:12:071068#endif
1069}
1070
[email protected]6d0146c2011-08-04 19:13:041071// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
[email protected]2588ea9d2011-08-22 20:59:531072// The history callback will call OnSavePageItemAddedToPersistentStore.
[email protected]6d0146c2011-08-04 19:13:041073// If the download finishes before the history callback,
[email protected]2588ea9d2011-08-22 20:59:531074// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring
1075// that the history event is update regardless of the order in which these two
1076// events complete.
[email protected]6d0146c2011-08-04 19:13:041077// If something removes the download item from the download manager (Remove,
1078// Shutdown) the result will be that the SavePage system will not be able to
1079// properly update the download item (which no longer exists) or the download
1080// history, but the action will complete properly anyway. This may lead to the
1081// history entry being wrong on a reload of chrome (specifically in the case of
1082// Initiation -> History Callback -> Removal -> Completion), but there's no way
1083// to solve that without canceling on Remove (which would then update the DB).
1084
[email protected]5656f8a2011-11-17 16:12:581085void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore(
1086 int32 download_id, int64 db_handle) {
[email protected]6d0146c2011-08-04 19:13:041087 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1088
1089 DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
1090 // This can happen if the download manager is shutting down and all maps
1091 // have been cleared.
1092 if (it == save_page_downloads_.end())
1093 return;
1094
1095 DownloadItem* download = it->second;
1096 if (!download) {
1097 NOTREACHED();
1098 return;
1099 }
1100
[email protected]0634626a2012-05-03 19:04:261101 DCHECK(!ContainsKey(history_downloads_, db_handle));
[email protected]d8472d92011-08-26 20:15:201102
[email protected]6d0146c2011-08-04 19:13:041103 AddDownloadItemToHistory(download, db_handle);
1104
1105 // Finalize this download if it finished before the history callback.
1106 if (!download->IsInProgress())
1107 SavePageDownloadFinished(download);
1108}
1109
[email protected]5656f8a2011-11-17 16:12:581110void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) {
[email protected]5009b7a2012-02-21 18:47:031111 if (download->IsPersisted()) {
[email protected]491aaa62012-06-07 03:50:181112 if (delegate_)
1113 delegate_->UpdateItemInPersistentStore(download);
[email protected]c09a8fd2011-11-21 19:54:501114 DCHECK(ContainsKey(save_page_downloads_, download->GetId()));
1115 save_page_downloads_.erase(download->GetId());
[email protected]6d0146c2011-08-04 19:13:041116
1117 if (download->IsComplete())
[email protected]ad50def52011-10-19 23:17:071118 content::NotificationService::current()->Notify(
[email protected]6d0146c2011-08-04 19:13:041119 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
[email protected]6c2381d2011-10-19 02:52:531120 content::Source<DownloadManager>(this),
1121 content::Details<DownloadItem>(download));
[email protected]6d0146c2011-08-04 19:13:041122 }
1123}
[email protected]da4a5582011-10-17 19:08:061124
[email protected]fc03de22011-12-06 23:28:121125void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
[email protected]491aaa62012-06-07 03:50:181126 if (delegate_)
1127 delegate_->UpdateItemInPersistentStore(download);
[email protected]da4a5582011-10-17 19:08:061128 int num_unopened = 0;
1129 for (DownloadMap::iterator it = history_downloads_.begin();
1130 it != history_downloads_.end(); ++it) {
[email protected]c09a8fd2011-11-21 19:54:501131 if (it->second->IsComplete() && !it->second->GetOpened())
[email protected]da4a5582011-10-17 19:08:061132 ++num_unopened;
1133 }
1134 download_stats::RecordOpensOutstanding(num_unopened);
1135}
[email protected]5656f8a2011-11-17 16:12:581136
[email protected]3d833de2012-05-30 23:32:061137void DownloadManagerImpl::DownloadRenamedToIntermediateName(
1138 DownloadItem* download) {
1139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1140 // If the rename failed, we receive an OnDownloadInterrupted() call before we
1141 // receive the DownloadRenamedToIntermediateName() call.
[email protected]491aaa62012-06-07 03:50:181142 if (delegate_)
1143 delegate_->AddItemToPersistentStore(download);
[email protected]3d833de2012-05-30 23:32:061144}
1145
1146void DownloadManagerImpl::DownloadRenamedToFinalName(
1147 DownloadItem* download) {
1148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1149 // If the rename failed, we receive an OnDownloadInterrupted() call before we
1150 // receive the DownloadRenamedToFinalName() call.
[email protected]491aaa62012-06-07 03:50:181151 if (delegate_) {
1152 delegate_->UpdatePathForItemInPersistentStore(
1153 download, download->GetFullPath());
1154 }
[email protected]3d833de2012-05-30 23:32:061155}
1156
[email protected]5948e1a2012-03-10 00:19:181157void DownloadManagerImpl::SetFileManagerForTesting(
1158 DownloadFileManager* file_manager) {
[email protected]5656f8a2011-11-17 16:12:581159 file_manager_ = file_manager;
1160}