blob: 5f87609cb6b5188d7956cd8fbe478abd0715c8ce [file] [log] [blame]
[email protected]a6e12012012-02-08 02:24:081// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]c09a8fd2011-11-21 19:54:502// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]18710a42a2012-10-17 19:50:435// File method ordering: Methods in this file are in the same order as
6// in download_item_impl.h, with the following exception: The public
[email protected]513b7e32012-11-30 21:02:377// interface Start is placed in chronological order with the other
8// (private) routines that together define a DownloadItem's state
9// transitions as the download progresses. See "Download progression
10// cascade" later in this file.
[email protected]4d4c5222012-09-06 19:29:2211
12// A regular DownloadItem (created for a download in this session of the
13// browser) normally goes through the following states:
14// * Created (when download starts)
15// * Destination filename determined
16// * Entered into the history database.
17// * Made visible in the download shelf.
18// * All the data is saved. Note that the actual data download occurs
19// in parallel with the above steps, but until those steps are
20// complete, the state of the data save will be ignored.
21// * Download file is renamed to its final name, and possibly
22// auto-opened.
23
[email protected]c09a8fd2011-11-21 19:54:5024#include "content/browser/download/download_item_impl.h"
25
26#include <vector>
27
28#include "base/basictypes.h"
29#include "base/bind.h"
[email protected]8d68a3e02013-01-12 15:57:1030#include "base/command_line.h"
[email protected]c09a8fd2011-11-21 19:54:5031#include "base/file_util.h"
32#include "base/format_macros.h"
[email protected]c09a8fd2011-11-21 19:54:5033#include "base/logging.h"
34#include "base/metrics/histogram.h"
[email protected]5bcef5c72011-12-07 23:03:2435#include "base/stl_util.h"
[email protected]c09a8fd2011-11-21 19:54:5036#include "base/stringprintf.h"
37#include "base/utf_string_conversions.h"
38#include "content/browser/download/download_create_info.h"
[email protected]f363dae2012-01-31 06:08:2339#include "content/browser/download/download_file.h"
[email protected]bf3b08a2012-03-08 01:52:3440#include "content/browser/download/download_interrupt_reasons_impl.h"
[email protected]db1d8f72012-07-13 19:23:1641#include "content/browser/download/download_item_impl_delegate.h"
[email protected]c09a8fd2011-11-21 19:54:5042#include "content/browser/download/download_request_handle.h"
43#include "content/browser/download/download_stats.h"
[email protected]8d68a3e02013-01-12 15:57:1044#include "content/browser/renderer_host/render_view_host_impl.h"
[email protected]93ddb3c2012-04-11 21:44:2945#include "content/browser/web_contents/web_contents_impl.h"
[email protected]8d68a3e02013-01-12 15:57:1046#include "content/public/browser/browser_context.h"
[email protected]c09a8fd2011-11-21 19:54:5047#include "content/public/browser/browser_thread.h"
48#include "content/public/browser/content_browser_client.h"
[email protected]cda79062013-01-17 01:50:5249#include "content/public/browser/download_danger_type.h"
[email protected]8d68a3e02013-01-12 15:57:1050#include "content/public/browser/download_interrupt_reasons.h"
51#include "content/public/browser/download_url_parameters.h"
52#include "content/public/common/content_switches.h"
53#include "content/public/common/referrer.h"
[email protected]c09a8fd2011-11-21 19:54:5054#include "net/base/net_util.h"
55
[email protected]35869622012-10-26 23:23:5556namespace content {
[email protected]8d68a3e02013-01-12 15:57:1057
[email protected]c09a8fd2011-11-21 19:54:5058namespace {
59
[email protected]8d68a3e02013-01-12 15:57:1060void DeleteDownloadedFile(const FilePath& path) {
[email protected]c09a8fd2011-11-21 19:54:5061 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
62
63 // Make sure we only delete files.
64 if (!file_util::DirectoryExists(path))
65 file_util::Delete(path, false);
66}
67
[email protected]c09a8fd2011-11-21 19:54:5068// Classes to null out request handle calls (for SavePage DownloadItems, which
69// may have, e.g., Cancel() called on them without it doing anything)
70// and to DCHECK on them (for history DownloadItems, which should never have
71// any operation that implies an off-thread component, since they don't
72// have any).
73class NullDownloadRequestHandle : public DownloadRequestHandleInterface {
74 public:
75 NullDownloadRequestHandle() {}
76
77 // DownloadRequestHandleInterface calls
[email protected]b172aee2012-04-10 17:05:2678 virtual WebContents* GetWebContents() const OVERRIDE {
[email protected]c09a8fd2011-11-21 19:54:5079 return NULL;
80 }
81 virtual DownloadManager* GetDownloadManager() const OVERRIDE {
82 return NULL;
83 }
84 virtual void PauseRequest() const OVERRIDE {}
85 virtual void ResumeRequest() const OVERRIDE {}
86 virtual void CancelRequest() const OVERRIDE {}
87 virtual std::string DebugString() const OVERRIDE {
88 return "Null DownloadRequestHandle";
89 }
90};
91
[email protected]53ac00e82012-10-18 20:59:2092// Wrapper around DownloadFile::Detach and DownloadFile::Cancel that
93// takes ownership of the DownloadFile and hence implicitly destroys it
94// at the end of the function.
[email protected]d6825972012-11-10 01:22:5295static void DownloadFileDetach(scoped_ptr<DownloadFile> download_file) {
[email protected]53ac00e82012-10-18 20:59:2096 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]d6825972012-11-10 01:22:5297 download_file->Detach();
[email protected]53ac00e82012-10-18 20:59:2098}
99
100static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
102 download_file->Cancel();
103}
104
[email protected]c09a8fd2011-11-21 19:54:50105} // namespace
106
[email protected]e582fdd2011-12-20 16:48:17107const char DownloadItem::kEmptyFileHash[] = "";
108
[email protected]8d68a3e02013-01-12 15:57:10109// The maximum number of attempts we will make to resume automatically.
110const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
111
[email protected]c09a8fd2011-11-21 19:54:50112// Constructor for reading from the history service.
[email protected]db1d8f72012-07-13 19:23:16113DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
[email protected]fc03de22011-12-06 23:28:12114 DownloadId download_id,
[email protected]3d95e542012-11-20 00:52:08115 const FilePath& path,
116 const GURL& url,
117 const GURL& referrer_url,
118 const base::Time& start_time,
119 const base::Time& end_time,
120 int64 received_bytes,
121 int64 total_bytes,
122 DownloadItem::DownloadState state,
123 bool opened,
[email protected]a6e12012012-02-08 02:24:08124 const net::BoundNetLog& bound_net_log)
[email protected]53ac00e82012-10-18 20:59:20125 : is_save_package_download_(false),
126 download_id_(download_id),
[email protected]3d95e542012-11-20 00:52:08127 current_path_(path),
128 target_path_(path),
[email protected]3d833de2012-05-30 23:32:06129 target_disposition_(TARGET_DISPOSITION_OVERWRITE),
[email protected]3d95e542012-11-20 00:52:08130 url_chain_(1, url),
131 referrer_url_(referrer_url),
[email protected]35869622012-10-26 23:23:55132 transition_type_(PAGE_TRANSITION_LINK),
[email protected]3d833de2012-05-30 23:32:06133 has_user_gesture_(false),
[email protected]3d95e542012-11-20 00:52:08134 total_bytes_(total_bytes),
135 received_bytes_(received_bytes),
[email protected]e384fd82011-11-30 06:37:20136 bytes_per_sec_(0),
[email protected]35869622012-10-26 23:23:55137 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
[email protected]c09a8fd2011-11-21 19:54:50138 start_tick_(base::TimeTicks()),
[email protected]3d95e542012-11-20 00:52:08139 state_(ExternalToInternalState(state)),
[email protected]35869622012-10-26 23:23:55140 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
[email protected]3d95e542012-11-20 00:52:08141 start_time_(start_time),
142 end_time_(end_time),
[email protected]fc03de22011-12-06 23:28:12143 delegate_(delegate),
[email protected]c09a8fd2011-11-21 19:54:50144 is_paused_(false),
[email protected]8d68a3e02013-01-12 15:57:10145 auto_resume_count_(0),
[email protected]c09a8fd2011-11-21 19:54:50146 open_when_complete_(false),
147 file_externally_removed_(false),
[email protected]c09a8fd2011-11-21 19:54:50148 auto_opened_(false),
[email protected]c09a8fd2011-11-21 19:54:50149 is_temporary_(false),
150 all_data_saved_(false),
[email protected]3d95e542012-11-20 00:52:08151 opened_(opened),
[email protected]a6e12012012-02-08 02:24:08152 delegate_delayed_complete_(false),
[email protected]3d833de2012-05-30 23:32:06153 bound_net_log_(bound_net_log),
154 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]fc03de22011-12-06 23:28:12155 delegate_->Attach();
[email protected]d0d368252012-09-24 17:13:42156 if (state_ == IN_PROGRESS_INTERNAL)
157 state_ = CANCELLED_INTERNAL;
158 if (state_ == COMPLETE_INTERNAL)
[email protected]c09a8fd2011-11-21 19:54:50159 all_data_saved_ = true;
[email protected]35869622012-10-26 23:23:55160 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
[email protected]c09a8fd2011-11-21 19:54:50161}
162
163// Constructing for a regular download:
164DownloadItemImpl::DownloadItemImpl(
[email protected]db1d8f72012-07-13 19:23:16165 DownloadItemImplDelegate* delegate,
[email protected]c09a8fd2011-11-21 19:54:50166 const DownloadCreateInfo& info,
[email protected]a6e12012012-02-08 02:24:08167 const net::BoundNetLog& bound_net_log)
[email protected]53ac00e82012-10-18 20:59:20168 : is_save_package_download_(false),
[email protected]c09a8fd2011-11-21 19:54:50169 download_id_(info.download_id),
[email protected]3d833de2012-05-30 23:32:06170 target_disposition_(
[email protected]3a2b2b5c2012-11-01 23:55:30171 (info.save_info->prompt_for_save_location) ?
[email protected]3d833de2012-05-30 23:32:06172 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE),
[email protected]c09a8fd2011-11-21 19:54:50173 url_chain_(info.url_chain),
174 referrer_url_(info.referrer_url),
[email protected]c873c862012-10-17 15:32:12175 suggested_filename_(UTF16ToUTF8(info.save_info->suggested_name)),
176 forced_file_path_(info.save_info->file_path),
[email protected]3d833de2012-05-30 23:32:06177 transition_type_(info.transition_type),
178 has_user_gesture_(info.has_user_gesture),
[email protected]c09a8fd2011-11-21 19:54:50179 content_disposition_(info.content_disposition),
180 mime_type_(info.mime_type),
181 original_mime_type_(info.original_mime_type),
[email protected]28aa2ed2011-12-06 06:27:38182 remote_address_(info.remote_address),
[email protected]c09a8fd2011-11-21 19:54:50183 total_bytes_(info.total_bytes),
184 received_bytes_(0),
[email protected]e384fd82011-11-30 06:37:20185 bytes_per_sec_(0),
[email protected]35869622012-10-26 23:23:55186 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
[email protected]c09a8fd2011-11-21 19:54:50187 start_tick_(base::TimeTicks::Now()),
[email protected]d0d368252012-09-24 17:13:42188 state_(IN_PROGRESS_INTERNAL),
[email protected]35869622012-10-26 23:23:55189 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
[email protected]c09a8fd2011-11-21 19:54:50190 start_time_(info.start_time),
[email protected]fc03de22011-12-06 23:28:12191 delegate_(delegate),
[email protected]c09a8fd2011-11-21 19:54:50192 is_paused_(false),
[email protected]8d68a3e02013-01-12 15:57:10193 auto_resume_count_(0),
[email protected]c09a8fd2011-11-21 19:54:50194 open_when_complete_(false),
195 file_externally_removed_(false),
[email protected]c09a8fd2011-11-21 19:54:50196 auto_opened_(false),
[email protected]c873c862012-10-17 15:32:12197 is_temporary_(!info.save_info->file_path.empty()),
[email protected]c09a8fd2011-11-21 19:54:50198 all_data_saved_(false),
199 opened_(false),
[email protected]a6e12012012-02-08 02:24:08200 delegate_delayed_complete_(false),
[email protected]3d833de2012-05-30 23:32:06201 bound_net_log_(bound_net_log),
202 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]fc03de22011-12-06 23:28:12203 delegate_->Attach();
[email protected]8d68a3e02013-01-12 15:57:10204 Init(true /* actively downloading */, SRC_ACTIVE_DOWNLOAD);
[email protected]ef17c9a2012-02-09 05:08:09205
206 // Link the event sources.
207 bound_net_log_.AddEvent(
208 net::NetLog::TYPE_DOWNLOAD_URL_REQUEST,
[email protected]2fa08912012-06-14 20:56:26209 info.request_bound_net_log.source().ToEventParametersCallback());
[email protected]ef17c9a2012-02-09 05:08:09210
211 info.request_bound_net_log.AddEvent(
212 net::NetLog::TYPE_DOWNLOAD_STARTED,
[email protected]2fa08912012-06-14 20:56:26213 bound_net_log_.source().ToEventParametersCallback());
[email protected]c09a8fd2011-11-21 19:54:50214}
215
216// Constructing for the "Save Page As..." feature:
[email protected]db1d8f72012-07-13 19:23:16217DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
[email protected]c09a8fd2011-11-21 19:54:50218 const FilePath& path,
219 const GURL& url,
[email protected]a6e12012012-02-08 02:24:08220 DownloadId download_id,
[email protected]6474b112012-05-04 19:35:27221 const std::string& mime_type,
[email protected]a6e12012012-02-08 02:24:08222 const net::BoundNetLog& bound_net_log)
[email protected]53ac00e82012-10-18 20:59:20223 : is_save_package_download_(true),
224 request_handle_(new NullDownloadRequestHandle()),
[email protected]c09a8fd2011-11-21 19:54:50225 download_id_(download_id),
[email protected]3d833de2012-05-30 23:32:06226 current_path_(path),
227 target_path_(path),
228 target_disposition_(TARGET_DISPOSITION_OVERWRITE),
[email protected]c09a8fd2011-11-21 19:54:50229 url_chain_(1, url),
230 referrer_url_(GURL()),
[email protected]35869622012-10-26 23:23:55231 transition_type_(PAGE_TRANSITION_LINK),
[email protected]3d833de2012-05-30 23:32:06232 has_user_gesture_(false),
[email protected]6474b112012-05-04 19:35:27233 mime_type_(mime_type),
234 original_mime_type_(mime_type),
[email protected]c09a8fd2011-11-21 19:54:50235 total_bytes_(0),
236 received_bytes_(0),
[email protected]e384fd82011-11-30 06:37:20237 bytes_per_sec_(0),
[email protected]35869622012-10-26 23:23:55238 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
[email protected]c09a8fd2011-11-21 19:54:50239 start_tick_(base::TimeTicks::Now()),
[email protected]d0d368252012-09-24 17:13:42240 state_(IN_PROGRESS_INTERNAL),
[email protected]35869622012-10-26 23:23:55241 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
[email protected]c09a8fd2011-11-21 19:54:50242 start_time_(base::Time::Now()),
[email protected]fc03de22011-12-06 23:28:12243 delegate_(delegate),
[email protected]c09a8fd2011-11-21 19:54:50244 is_paused_(false),
[email protected]8d68a3e02013-01-12 15:57:10245 auto_resume_count_(0),
[email protected]c09a8fd2011-11-21 19:54:50246 open_when_complete_(false),
247 file_externally_removed_(false),
[email protected]c09a8fd2011-11-21 19:54:50248 auto_opened_(false),
[email protected]c09a8fd2011-11-21 19:54:50249 is_temporary_(false),
250 all_data_saved_(false),
251 opened_(false),
[email protected]a6e12012012-02-08 02:24:08252 delegate_delayed_complete_(false),
[email protected]3d833de2012-05-30 23:32:06253 bound_net_log_(bound_net_log),
254 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]fc03de22011-12-06 23:28:12255 delegate_->Attach();
[email protected]35869622012-10-26 23:23:55256 Init(true /* actively downloading */, SRC_SAVE_PAGE_AS);
[email protected]c09a8fd2011-11-21 19:54:50257}
258
259DownloadItemImpl::~DownloadItemImpl() {
[email protected]0634626a2012-05-03 19:04:26260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]53ac00e82012-10-18 20:59:20261
262 // Should always have been nuked before now, at worst in
263 // DownloadManager shutdown.
264 DCHECK(!download_file_.get());
265
[email protected]7e834f02012-08-09 20:38:56266 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
[email protected]fc03de22011-12-06 23:28:12267 delegate_->AssertStateConsistent(this);
268 delegate_->Detach();
[email protected]c09a8fd2011-11-21 19:54:50269}
270
271void DownloadItemImpl::AddObserver(Observer* observer) {
[email protected]0634626a2012-05-03 19:04:26272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50273
274 observers_.AddObserver(observer);
275}
276
277void DownloadItemImpl::RemoveObserver(Observer* observer) {
[email protected]0634626a2012-05-03 19:04:26278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50279
280 observers_.RemoveObserver(observer);
281}
282
283void DownloadItemImpl::UpdateObservers() {
[email protected]0634626a2012-05-03 19:04:26284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50285
286 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
287}
288
[email protected]4d4c5222012-09-06 19:29:22289void DownloadItemImpl::DangerousDownloadValidated() {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]db6234e2012-09-25 17:23:01291 DCHECK_EQ(IN_PROGRESS, GetState());
[email protected]cda79062013-01-17 01:50:52292 DCHECK(IsDangerous());
[email protected]4d4c5222012-09-06 19:29:22293
[email protected]3d95e542012-11-20 00:52:08294 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
295
[email protected]db6234e2012-09-25 17:23:01296 if (GetState() != IN_PROGRESS)
297 return;
298
[email protected]4d4c5222012-09-06 19:29:22299 UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated",
300 GetDangerType(),
[email protected]35869622012-10-26 23:23:55301 DOWNLOAD_DANGER_TYPE_MAX);
[email protected]4d4c5222012-09-06 19:29:22302
[email protected]cda79062013-01-17 01:50:52303 danger_type_ = DOWNLOAD_DANGER_TYPE_USER_VALIDATED;
[email protected]4d4c5222012-09-06 19:29:22304
305 bound_net_log_.AddEvent(
306 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
[email protected]cda79062013-01-17 01:50:52307 base::Bind(&ItemCheckedNetLogCallback, GetDangerType()));
[email protected]4d4c5222012-09-06 19:29:22308
309 UpdateObservers();
310
[email protected]18710a42a2012-10-17 19:50:43311 MaybeCompleteDownload();
[email protected]c09a8fd2011-11-21 19:54:50312}
313
[email protected]f9dcbcf2013-01-07 18:03:18314void DownloadItemImpl::Pause() {
[email protected]4d4c5222012-09-06 19:29:22315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]53ac00e82012-10-18 20:59:20316
[email protected]f9dcbcf2013-01-07 18:03:18317 // Ignore irrelevant states.
318 if (state_ != IN_PROGRESS_INTERNAL || is_paused_)
[email protected]53ac00e82012-10-18 20:59:20319 return;
320
[email protected]f9dcbcf2013-01-07 18:03:18321 request_handle_->PauseRequest();
322 is_paused_ = true;
323 UpdateObservers();
324}
325
326void DownloadItemImpl::Resume() {
327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
328
329 // Ignore irrelevant states.
[email protected]8d68a3e02013-01-12 15:57:10330 if (state_ == COMPLETE_INTERNAL || state_ == COMPLETING_INTERNAL ||
331 !is_paused_)
[email protected]f9dcbcf2013-01-07 18:03:18332 return;
333
[email protected]8d68a3e02013-01-12 15:57:10334 if (state_ == INTERRUPTED_INTERNAL) {
335 auto_resume_count_ = 0; // User input resets the counter.
336 ResumeInterruptedDownload();
337 return;
338 }
339 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
340
[email protected]f9dcbcf2013-01-07 18:03:18341 request_handle_->ResumeRequest();
342 is_paused_ = false;
[email protected]4d4c5222012-09-06 19:29:22343 UpdateObservers();
[email protected]c09a8fd2011-11-21 19:54:50344}
345
[email protected]4d4c5222012-09-06 19:29:22346void DownloadItemImpl::Cancel(bool user_cancel) {
347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
348
[email protected]4d4c5222012-09-06 19:29:22349 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
[email protected]8d68a3e02013-01-12 15:57:10350 if (state_ != IN_PROGRESS_INTERNAL && state_ != INTERRUPTED_INTERNAL) {
[email protected]4d4c5222012-09-06 19:29:22351 // Small downloads might be complete before this method has
352 // a chance to run.
353 return;
354 }
355
[email protected]8d68a3e02013-01-12 15:57:10356 last_reason_ = user_cancel ?
357 DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
358 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
359
[email protected]35869622012-10-26 23:23:55360 RecordDownloadCount(CANCELLED_COUNT);
[email protected]4d4c5222012-09-06 19:29:22361
[email protected]53ac00e82012-10-18 20:59:20362 CancelDownloadFile();
363
[email protected]b882211a2013-01-15 07:50:09364 if (state_ != INTERRUPTED_INTERNAL) {
365 // Cancel the originating URL request unless it's already been cancelled
366 // by interrupt.
367 request_handle_->CancelRequest();
368 }
369
370 TransitionTo(CANCELLED_INTERNAL);
[email protected]4d4c5222012-09-06 19:29:22371}
372
373void DownloadItemImpl::Delete(DeleteReason reason) {
[email protected]8d68a3e02013-01-12 15:57:10374 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
[email protected]4d4c5222012-09-06 19:29:22375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
376
377 switch (reason) {
378 case DELETE_DUE_TO_USER_DISCARD:
379 UMA_HISTOGRAM_ENUMERATION(
380 "Download.UserDiscard", GetDangerType(),
[email protected]35869622012-10-26 23:23:55381 DOWNLOAD_DANGER_TYPE_MAX);
[email protected]4d4c5222012-09-06 19:29:22382 break;
383 case DELETE_DUE_TO_BROWSER_SHUTDOWN:
384 UMA_HISTOGRAM_ENUMERATION(
385 "Download.Discard", GetDangerType(),
[email protected]35869622012-10-26 23:23:55386 DOWNLOAD_DANGER_TYPE_MAX);
[email protected]4d4c5222012-09-06 19:29:22387 break;
388 default:
389 NOTREACHED();
390 }
391
[email protected]53ac00e82012-10-18 20:59:20392 // Delete the file if it exists and is not owned by a DownloadFile object.
393 // (In the latter case the DownloadFile object will delete it on cancel.)
394 if (!current_path_.empty() && download_file_.get() == NULL) {
[email protected]4d4c5222012-09-06 19:29:22395 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
396 base::Bind(&DeleteDownloadedFile, current_path_));
[email protected]53ac00e82012-10-18 20:59:20397 }
[email protected]4d4c5222012-09-06 19:29:22398 Remove();
399 // We have now been deleted.
400}
401
402void DownloadItemImpl::Remove() {
[email protected]8d68a3e02013-01-12 15:57:10403 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
[email protected]4d4c5222012-09-06 19:29:22404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405
406 delegate_->AssertStateConsistent(this);
407 Cancel(true);
408 delegate_->AssertStateConsistent(this);
409
410 NotifyRemoved();
411 delegate_->DownloadRemoved(this);
412 // We have now been deleted.
[email protected]c09a8fd2011-11-21 19:54:50413}
414
415void DownloadItemImpl::OpenDownload() {
[email protected]0634626a2012-05-03 19:04:26416 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50417
[email protected]d0d368252012-09-24 17:13:42418 if (state_ == IN_PROGRESS_INTERNAL) {
[email protected]71f55842012-03-24 04:09:02419 // We don't honor the open_when_complete_ flag for temporary
420 // downloads. Don't set it because it shows up in the UI.
421 if (!IsTemporary())
422 open_when_complete_ = !open_when_complete_;
[email protected]c09a8fd2011-11-21 19:54:50423 return;
424 }
425
[email protected]d0d368252012-09-24 17:13:42426 if (state_ != COMPLETE_INTERNAL || file_externally_removed_)
[email protected]c09a8fd2011-11-21 19:54:50427 return;
428
429 // Ideally, we want to detect errors in opening and report them, but we
430 // don't generally have the proper interface for that to the external
431 // program that opens the file. So instead we spawn a check to update
432 // the UI if the file has been deleted in parallel with the open.
[email protected]fc03de22011-12-06 23:28:12433 delegate_->CheckForFileRemoval(this);
[email protected]35869622012-10-26 23:23:55434 RecordOpen(GetEndTime(), !GetOpened());
[email protected]c09a8fd2011-11-21 19:54:50435 opened_ = true;
436 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
[email protected]ffc0c2d2013-01-21 15:32:12437 delegate_->OpenDownload(this);
[email protected]c09a8fd2011-11-21 19:54:50438}
439
440void DownloadItemImpl::ShowDownloadInShell() {
[email protected]0634626a2012-05-03 19:04:26441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50442
[email protected]ffc0c2d2013-01-21 15:32:12443 delegate_->ShowDownloadInShell(this);
[email protected]c09a8fd2011-11-21 19:54:50444}
445
[email protected]4d4c5222012-09-06 19:29:22446int32 DownloadItemImpl::GetId() const {
447 return download_id_.local();
[email protected]c09a8fd2011-11-21 19:54:50448}
449
[email protected]4d4c5222012-09-06 19:29:22450DownloadId DownloadItemImpl::GetGlobalId() const {
451 return download_id_;
452}
453
[email protected]4d4c5222012-09-06 19:29:22454DownloadItem::DownloadState DownloadItemImpl::GetState() const {
[email protected]d0d368252012-09-24 17:13:42455 return InternalToExternalState(state_);
[email protected]4d4c5222012-09-06 19:29:22456}
457
[email protected]35869622012-10-26 23:23:55458DownloadInterruptReason DownloadItemImpl::GetLastReason() const {
[email protected]4d4c5222012-09-06 19:29:22459 return last_reason_;
460}
461
462bool DownloadItemImpl::IsPaused() const {
463 return is_paused_;
464}
465
466bool DownloadItemImpl::IsTemporary() const {
467 return is_temporary_;
468}
469
[email protected]b882211a2013-01-15 07:50:09470// TODO(rdsmith): Figure out whether or not we want this probe routine
471// to consider interrupted (resumably) downloads partial downloads.
472// Conceptually the answer is probably yes, but everywhere that currently
473// uses the routine is using it as a synonym for IsInProgress().
[email protected]4d4c5222012-09-06 19:29:22474bool DownloadItemImpl::IsPartialDownload() const {
[email protected]8d68a3e02013-01-12 15:57:10475 DownloadState state = InternalToExternalState(state_);
[email protected]b882211a2013-01-15 07:50:09476 return (state == IN_PROGRESS);
[email protected]4d4c5222012-09-06 19:29:22477}
478
479bool DownloadItemImpl::IsInProgress() const {
[email protected]d0d368252012-09-24 17:13:42480 return InternalToExternalState(state_) == IN_PROGRESS;
[email protected]4d4c5222012-09-06 19:29:22481}
482
483bool DownloadItemImpl::IsCancelled() const {
[email protected]8d68a3e02013-01-12 15:57:10484 return InternalToExternalState(state_) == CANCELLED;
[email protected]4d4c5222012-09-06 19:29:22485}
486
487bool DownloadItemImpl::IsInterrupted() const {
[email protected]d0d368252012-09-24 17:13:42488 return InternalToExternalState(state_) == INTERRUPTED;
[email protected]4d4c5222012-09-06 19:29:22489}
490
491bool DownloadItemImpl::IsComplete() const {
[email protected]d0d368252012-09-24 17:13:42492 return InternalToExternalState(state_) == COMPLETE;
[email protected]4d4c5222012-09-06 19:29:22493}
494
495const GURL& DownloadItemImpl::GetURL() const {
496 return url_chain_.empty() ?
497 GURL::EmptyGURL() : url_chain_.back();
498}
499
500const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const {
501 return url_chain_;
502}
503
504const GURL& DownloadItemImpl::GetOriginalUrl() const {
505 return url_chain_.front();
506}
507
508const GURL& DownloadItemImpl::GetReferrerUrl() const {
509 return referrer_url_;
510}
511
512std::string DownloadItemImpl::GetSuggestedFilename() const {
513 return suggested_filename_;
514}
515
516std::string DownloadItemImpl::GetContentDisposition() const {
517 return content_disposition_;
518}
519
520std::string DownloadItemImpl::GetMimeType() const {
521 return mime_type_;
522}
523
524std::string DownloadItemImpl::GetOriginalMimeType() const {
525 return original_mime_type_;
526}
527
[email protected]4d4c5222012-09-06 19:29:22528std::string DownloadItemImpl::GetRemoteAddress() const {
529 return remote_address_;
530}
531
532bool DownloadItemImpl::HasUserGesture() const {
533 return has_user_gesture_;
534};
535
[email protected]35869622012-10-26 23:23:55536PageTransition DownloadItemImpl::GetTransitionType() const {
[email protected]4d4c5222012-09-06 19:29:22537 return transition_type_;
538};
539
540const std::string& DownloadItemImpl::GetLastModifiedTime() const {
541 return last_modified_time_;
542}
543
544const std::string& DownloadItemImpl::GetETag() const {
545 return etag_;
546}
547
[email protected]fb904eb52012-11-05 18:54:55548bool DownloadItemImpl::IsSavePackageDownload() const {
549 return is_save_package_download_;
550}
551
[email protected]4d4c5222012-09-06 19:29:22552const FilePath& DownloadItemImpl::GetFullPath() const {
553 return current_path_;
554}
555
556const FilePath& DownloadItemImpl::GetTargetFilePath() const {
557 return target_path_;
558}
559
[email protected]4d4c5222012-09-06 19:29:22560const FilePath& DownloadItemImpl::GetForcedFilePath() const {
561 // TODO(asanka): Get rid of GetForcedFilePath(). We should instead just
562 // require that clients respect GetTargetFilePath() if it is already set.
563 return forced_file_path_;
564}
565
[email protected]cda79062013-01-17 01:50:52566// TODO(asanka): Get rid of GetUserVerifiedFilePath(). http://crbug.com/134237.
[email protected]4d4c5222012-09-06 19:29:22567FilePath DownloadItemImpl::GetUserVerifiedFilePath() const {
[email protected]cda79062013-01-17 01:50:52568 return (IsDangerous() ||
569 danger_type_ == DOWNLOAD_DANGER_TYPE_USER_VALIDATED) ?
570 GetFullPath() : GetTargetFilePath();
[email protected]4d4c5222012-09-06 19:29:22571}
572
573FilePath DownloadItemImpl::GetFileNameToReportUser() const {
574 if (!display_name_.empty())
575 return display_name_;
576 return target_path_.BaseName();
577}
578
579DownloadItem::TargetDisposition DownloadItemImpl::GetTargetDisposition() const {
580 return target_disposition_;
581}
582
583const std::string& DownloadItemImpl::GetHash() const {
584 return hash_;
585}
586
587const std::string& DownloadItemImpl::GetHashState() const {
588 return hash_state_;
589}
590
591bool DownloadItemImpl::GetFileExternallyRemoved() const {
592 return file_externally_removed_;
593}
594
[email protected]4d4c5222012-09-06 19:29:22595bool DownloadItemImpl::IsDangerous() const {
[email protected]ae4a1b22013-01-08 18:45:36596#ifdef OS_WIN
[email protected]4d4c5222012-09-06 19:29:22597 // TODO(noelutz): At this point only the windows views UI supports
598 // warnings based on dangerous content.
[email protected]35869622012-10-26 23:23:55599 return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
600 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
601 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
602 danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT);
[email protected]4d4c5222012-09-06 19:29:22603#else
[email protected]35869622012-10-26 23:23:55604 return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
605 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
[email protected]4d4c5222012-09-06 19:29:22606#endif
607}
608
[email protected]35869622012-10-26 23:23:55609DownloadDangerType DownloadItemImpl::GetDangerType() const {
[email protected]4d4c5222012-09-06 19:29:22610 return danger_type_;
611}
612
613bool DownloadItemImpl::TimeRemaining(base::TimeDelta* remaining) const {
614 if (total_bytes_ <= 0)
615 return false; // We never received the content_length for this download.
616
617 int64 speed = CurrentSpeed();
618 if (speed == 0)
619 return false;
620
621 *remaining = base::TimeDelta::FromSeconds(
622 (total_bytes_ - received_bytes_) / speed);
623 return true;
624}
625
626int64 DownloadItemImpl::CurrentSpeed() const {
627 if (is_paused_)
628 return 0;
629 return bytes_per_sec_;
630}
631
632int DownloadItemImpl::PercentComplete() const {
633 // If the delegate is delaying completion of the download, then we have no
634 // idea how long it will take.
635 if (delegate_delayed_complete_ || total_bytes_ <= 0)
636 return -1;
637
638 return static_cast<int>(received_bytes_ * 100.0 / total_bytes_);
639}
640
641bool DownloadItemImpl::AllDataSaved() const {
642 return all_data_saved_;
643}
644
645int64 DownloadItemImpl::GetTotalBytes() const {
646 return total_bytes_;
647}
648
649int64 DownloadItemImpl::GetReceivedBytes() const {
650 return received_bytes_;
651}
652
653base::Time DownloadItemImpl::GetStartTime() const {
654 return start_time_;
655}
656
657base::Time DownloadItemImpl::GetEndTime() const {
658 return end_time_;
659}
660
661bool DownloadItemImpl::CanShowInFolder() {
[email protected]35b176f2012-12-27 01:38:03662 // A download can be shown in the folder if the downloaded file is in a known
663 // location.
664 return CanOpenDownload() && !GetFullPath().empty();
[email protected]4d4c5222012-09-06 19:29:22665}
666
667bool DownloadItemImpl::CanOpenDownload() {
[email protected]35b176f2012-12-27 01:38:03668 // We can open the file or mark it for opening on completion if the download
669 // is expected to complete successfully. Exclude temporary downloads, since
670 // they aren't owned by the download system.
671 return (IsInProgress() || IsComplete()) && !IsTemporary() &&
672 !file_externally_removed_;
[email protected]4d4c5222012-09-06 19:29:22673}
674
675bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
676 return delegate_->ShouldOpenFileBasedOnExtension(GetUserVerifiedFilePath());
677}
678
679bool DownloadItemImpl::GetOpenWhenComplete() const {
680 return open_when_complete_;
681}
682
683bool DownloadItemImpl::GetAutoOpened() {
684 return auto_opened_;
685}
686
687bool DownloadItemImpl::GetOpened() const {
688 return opened_;
689}
690
[email protected]35869622012-10-26 23:23:55691BrowserContext* DownloadItemImpl::GetBrowserContext() const {
[email protected]4d4c5222012-09-06 19:29:22692 return delegate_->GetBrowserContext();
693}
694
695WebContents* DownloadItemImpl::GetWebContents() const {
696 // TODO(rdsmith): Remove null check after removing GetWebContents() from
697 // paths that might be used by DownloadItems created from history import.
698 // Currently such items have null request_handle_s, where other items
699 // (regular and SavePackage downloads) have actual objects off the pointer.
700 if (request_handle_.get())
701 return request_handle_->GetWebContents();
702 return NULL;
703}
704
[email protected]35869622012-10-26 23:23:55705void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) {
[email protected]96c3bdbaa2012-08-31 16:39:54706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4d4c5222012-09-06 19:29:22707 DCHECK(AllDataSaved());
[email protected]3d95e542012-11-20 00:52:08708 VLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
709 << " download=" << DebugString(true);
[email protected]4d4c5222012-09-06 19:29:22710 SetDangerType(danger_type);
711 UpdateObservers();
712}
[email protected]96c3bdbaa2012-08-31 16:39:54713
[email protected]4d4c5222012-09-06 19:29:22714void DownloadItemImpl::SetOpenWhenComplete(bool open) {
715 open_when_complete_ = open;
716}
[email protected]96c3bdbaa2012-08-31 16:39:54717
[email protected]4d4c5222012-09-06 19:29:22718void DownloadItemImpl::SetIsTemporary(bool temporary) {
719 is_temporary_ = temporary;
720}
[email protected]96c3bdbaa2012-08-31 16:39:54721
[email protected]4d4c5222012-09-06 19:29:22722void DownloadItemImpl::SetOpened(bool opened) {
723 opened_ = opened;
724}
725
726void DownloadItemImpl::SetDisplayName(const FilePath& name) {
727 display_name_ = name;
728}
729
730std::string DownloadItemImpl::DebugString(bool verbose) const {
731 std::string description =
732 base::StringPrintf("{ id = %d"
733 " state = %s",
734 download_id_.local(),
[email protected]d0d368252012-09-24 17:13:42735 DebugDownloadStateString(state_));
[email protected]4d4c5222012-09-06 19:29:22736
737 // Construct a string of the URL chain.
738 std::string url_list("<none>");
739 if (!url_chain_.empty()) {
740 std::vector<GURL>::const_iterator iter = url_chain_.begin();
741 std::vector<GURL>::const_iterator last = url_chain_.end();
742 url_list = (*iter).spec();
743 ++iter;
744 for ( ; verbose && (iter != last); ++iter) {
745 url_list += " ->\n\t";
746 const GURL& next_url = *iter;
747 url_list += next_url.spec();
748 }
749 }
750
751 if (verbose) {
752 description += base::StringPrintf(
[email protected]4d4c5222012-09-06 19:29:22753 " total = %" PRId64
754 " received = %" PRId64
755 " reason = %s"
756 " paused = %c"
[email protected]8d68a3e02013-01-12 15:57:10757 " resume_mode = %s"
758 " auto_resume_count = %d"
[email protected]cda79062013-01-17 01:50:52759 " danger = %d"
[email protected]8d68a3e02013-01-12 15:57:10760 " all_data_saved = %c"
[email protected]4d4c5222012-09-06 19:29:22761 " last_modified = '%s'"
762 " etag = '%s'"
[email protected]8d68a3e02013-01-12 15:57:10763 " has_download_file = %s"
[email protected]4d4c5222012-09-06 19:29:22764 " url_chain = \n\t\"%s\"\n\t"
[email protected]8d68a3e02013-01-12 15:57:10765 " full_path = \"%" PRFilePath "\"\n\t"
766 " target_path = \"%" PRFilePath "\"",
[email protected]4d4c5222012-09-06 19:29:22767 GetTotalBytes(),
768 GetReceivedBytes(),
769 InterruptReasonDebugString(last_reason_).c_str(),
770 IsPaused() ? 'T' : 'F',
[email protected]8d68a3e02013-01-12 15:57:10771 DebugResumeModeString(GetResumeMode()),
772 auto_resume_count_,
[email protected]cda79062013-01-17 01:50:52773 GetDangerType(),
[email protected]8d68a3e02013-01-12 15:57:10774 AllDataSaved() ? 'T' : 'F',
[email protected]4d4c5222012-09-06 19:29:22775 GetLastModifiedTime().c_str(),
776 GetETag().c_str(),
[email protected]8d68a3e02013-01-12 15:57:10777 download_file_.get() ? "true" : "false",
[email protected]4d4c5222012-09-06 19:29:22778 url_list.c_str(),
779 GetFullPath().value().c_str(),
[email protected]8d68a3e02013-01-12 15:57:10780 GetTargetFilePath().value().c_str());
[email protected]4d4c5222012-09-06 19:29:22781 } else {
782 description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
783 }
784
785 description += " }";
786
787 return description;
788}
789
[email protected]8d68a3e02013-01-12 15:57:10790DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
791 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
792 if (!IsInterrupted())
793 return RESUME_MODE_INVALID;
794
795 // We can't continue without a handle on the intermediate file.
796 const bool force_restart = current_path_.empty();
797
798 // We won't auto-restart if we've used up our attempts or the
799 // download has been paused by user action.
800 const bool force_user =
801 (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_);
802
803 ResumeMode mode = RESUME_MODE_INVALID;
804
805 switch(last_reason_) {
806 case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
807 case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
808 if (force_restart && force_user)
809 mode = RESUME_MODE_USER_RESTART;
810 else if (force_restart)
811 mode = RESUME_MODE_IMMEDIATE_RESTART;
812 else if (force_user)
813 mode = RESUME_MODE_USER_CONTINUE;
814 else
815 mode = RESUME_MODE_IMMEDIATE_CONTINUE;
816 break;
817
818 case DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
819 case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
820 case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
821 if (force_user)
822 mode = RESUME_MODE_USER_RESTART;
823 else
824 mode = RESUME_MODE_IMMEDIATE_RESTART;
825 break;
826
827 case DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
828 case DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
829 case DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
830 case DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
831 case DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
832 case DOWNLOAD_INTERRUPT_REASON_CRASH:
833 if (force_restart)
834 mode = RESUME_MODE_USER_RESTART;
835 else
836 mode = RESUME_MODE_USER_CONTINUE;
837 break;
838
839 case DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
840 case DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
841 case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
842 case DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
843 case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
844 mode = RESUME_MODE_USER_RESTART;
845 break;
846
847 case DOWNLOAD_INTERRUPT_REASON_NONE:
848 case DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
849 case DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
850 case DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
851 case DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
852 case DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
853 mode = RESUME_MODE_INVALID;
854 break;
855 }
856
857 return mode;
858}
859
860void DownloadItemImpl::ResumeInterruptedDownload() {
861 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
862
863 // If the flag for downloads resumption isn't enabled, ignore
864 // this request.
865 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
866 if (!command_line.HasSwitch(switches::kEnableDownloadResumption))
867 return;
868
869 // Handle the case of clicking 'Resume' in the download shelf.
870 DCHECK(IsInterrupted());
871
872 DVLOG(20) << __FUNCTION__ << "()" << DebugString(true);
873
874 // If we can't get a web contents, we can't resume the download.
875 // TODO(rdsmith): Find some alternative web contents to use--this
876 // means we can't restart a download if it's a download imported
877 // from the history.
878 if (!GetWebContents())
879 return;
880
881 // Reset the appropriate state if restarting.
882 ResumeMode mode = GetResumeMode();
883 if (mode == RESUME_MODE_IMMEDIATE_RESTART ||
884 mode == RESUME_MODE_USER_RESTART) {
885 received_bytes_ = 0;
886 hash_state_ = "";
887 last_modified_time_ = "";
888 etag_ = "";
889 }
890
891 scoped_ptr<DownloadUrlParameters> download_params(
892 DownloadUrlParameters::FromWebContents(GetWebContents(),
893 GetOriginalUrl()));
894
895 download_params->set_file_path(GetFullPath());
896 download_params->set_offset(GetReceivedBytes());
897 download_params->set_hash_state(GetHashState());
898 download_params->set_last_modified(GetLastModifiedTime());
899 download_params->set_etag(GetETag());
900
901 delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId());
902
903 // Just in case we were interrupted while paused.
904 is_paused_ = false;
905}
906
[email protected]4d4c5222012-09-06 19:29:22907void DownloadItemImpl::NotifyRemoved() {
908 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
909}
910
911void DownloadItemImpl::OnDownloadedFileRemoved() {
912 file_externally_removed_ = true;
[email protected]3d95e542012-11-20 00:52:08913 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]4d4c5222012-09-06 19:29:22914 UpdateObservers();
915}
916
[email protected]35869622012-10-26 23:23:55917base::WeakPtr<DownloadDestinationObserver>
[email protected]53ac00e82012-10-18 20:59:20918DownloadItemImpl::DestinationObserverAsWeakPtr() {
919 return weak_ptr_factory_.GetWeakPtr();
920}
921
[email protected]8d68a3e02013-01-12 15:57:10922const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
923 return bound_net_log_;
924}
925
[email protected]4d4c5222012-09-06 19:29:22926void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
927 total_bytes_ = total_bytes;
[email protected]96c3bdbaa2012-08-31 16:39:54928}
929
[email protected]16dcd302012-07-02 17:16:51930// Updates from the download thread may have been posted while this download
931// was being cancelled in the UI thread, so we'll accept them unless we're
932// complete.
[email protected]443853c62011-12-22 19:22:41933void DownloadItemImpl::UpdateProgress(int64 bytes_so_far,
[email protected]16dcd302012-07-02 17:16:51934 int64 bytes_per_sec,
[email protected]443853c62011-12-22 19:22:41935 const std::string& hash_state) {
[email protected]16dcd302012-07-02 17:16:51936 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d95e542012-11-20 00:52:08937 VLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
938 << " per_sec=" << bytes_per_sec << " download=" << DebugString(true);
[email protected]336721e2012-06-29 08:09:38939
[email protected]d0d368252012-09-24 17:13:42940 if (state_ != IN_PROGRESS_INTERNAL) {
[email protected]16dcd302012-07-02 17:16:51941 // Ignore if we're no longer in-progress. This can happen if we race a
942 // Cancel on the UI thread with an update on the FILE thread.
943 //
944 // TODO(rdsmith): Arguably we should let this go through, as this means
945 // the download really did get further than we know before it was
946 // cancelled. But the gain isn't very large, and the code is more
947 // fragile if it has to support in progress updates in a non-in-progress
948 // state. This issue should be readdressed when we revamp performance
949 // reporting.
950 return;
951 }
952 bytes_per_sec_ = bytes_per_sec;
953 hash_state_ = hash_state;
[email protected]c09a8fd2011-11-21 19:54:50954 received_bytes_ = bytes_so_far;
955
956 // If we've received more data than we were expecting (bad server info?),
957 // revert to 'unknown size mode'.
958 if (received_bytes_ > total_bytes_)
959 total_bytes_ = 0;
[email protected]a6e12012012-02-08 02:24:08960
961 if (bound_net_log_.IsLoggingAllEvents()) {
962 bound_net_log_.AddEvent(
963 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
[email protected]2fa08912012-06-14 20:56:26964 net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
[email protected]a6e12012012-02-08 02:24:08965 }
[email protected]c09a8fd2011-11-21 19:54:50966
[email protected]c09a8fd2011-11-21 19:54:50967 UpdateObservers();
968}
969
[email protected]53ac00e82012-10-18 20:59:20970void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
[email protected]0634626a2012-05-03 19:04:26971 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50972
[email protected]53ac00e82012-10-18 20:59:20973 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
[email protected]c09a8fd2011-11-21 19:54:50974 DCHECK(!all_data_saved_);
975 all_data_saved_ = true;
[email protected]3d95e542012-11-20 00:52:08976 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]53ac00e82012-10-18 20:59:20977
978 // Store final hash and null out intermediate serialized hash state.
979 hash_ = final_hash;
980 hash_state_ = "";
981
[email protected]196e9722012-03-28 05:14:04982 UpdateObservers();
[email protected]c09a8fd2011-11-21 19:54:50983}
984
[email protected]4d4c5222012-09-06 19:29:22985void DownloadItemImpl::MarkAsComplete() {
986 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
987
988 DCHECK(all_data_saved_);
989 end_time_ = base::Time::Now();
[email protected]d0d368252012-09-24 17:13:42990 TransitionTo(COMPLETE_INTERNAL);
[email protected]4d4c5222012-09-06 19:29:22991}
[email protected]53ac00e82012-10-18 20:59:20992void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far,
993 int64 bytes_per_sec,
994 const std::string& hash_state) {
995 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d95e542012-11-20 00:52:08996 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]53ac00e82012-10-18 20:59:20997
998 if (!IsInProgress()) {
999 // Ignore if we're no longer in-progress. This can happen if we race a
1000 // Cancel on the UI thread with an update on the FILE thread.
1001 //
1002 // TODO(rdsmith): Arguably we should let this go through, as this means
1003 // the download really did get further than we know before it was
1004 // cancelled. But the gain isn't very large, and the code is more
1005 // fragile if it has to support in progress updates in a non-in-progress
1006 // state. This issue should be readdressed when we revamp performance
1007 // reporting.
1008 return;
1009 }
1010 bytes_per_sec_ = bytes_per_sec;
1011 hash_state_ = hash_state;
1012 received_bytes_ = bytes_so_far;
1013
1014 // If we've received more data than we were expecting (bad server info?),
1015 // revert to 'unknown size mode'.
1016 if (received_bytes_ > total_bytes_)
1017 total_bytes_ = 0;
1018
1019 if (bound_net_log_.IsLoggingAllEvents()) {
1020 bound_net_log_.AddEvent(
1021 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
1022 net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
1023 }
1024
1025 UpdateObservers();
1026}
1027
[email protected]35869622012-10-26 23:23:551028void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
[email protected]53ac00e82012-10-18 20:59:201029 // The DestinationError and Interrupt routines are being kept separate
[email protected]3d95e542012-11-20 00:52:081030 // to allow for a future merging of the Cancel and Interrupt routines.
[email protected]53ac00e82012-10-18 20:59:201031 Interrupt(reason);
1032}
1033
1034void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
[email protected]3d95e542012-11-20 00:52:081035 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]53ac00e82012-10-18 20:59:201036 if (!IsInProgress())
1037 return;
1038 OnAllDataSaved(final_hash);
1039 MaybeCompleteDownload();
1040}
1041
[email protected]4d4c5222012-09-06 19:29:221042// **** Download progression cascade
1043
1044void DownloadItemImpl::Init(bool active,
[email protected]35869622012-10-26 23:23:551045 DownloadType download_type) {
[email protected]4d4c5222012-09-06 19:29:221046 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1047
1048 if (active)
[email protected]35869622012-10-26 23:23:551049 RecordDownloadCount(START_COUNT);
[email protected]4d4c5222012-09-06 19:29:221050
1051 if (target_path_.empty())
1052 target_path_ = current_path_;
1053 std::string file_name;
[email protected]35869622012-10-26 23:23:551054 if (download_type == SRC_HISTORY_IMPORT) {
[email protected]4d4c5222012-09-06 19:29:221055 // target_path_ works for History and Save As versions.
1056 file_name = target_path_.AsUTF8Unsafe();
1057 } else {
1058 // See if it's set programmatically.
1059 file_name = forced_file_path_.AsUTF8Unsafe();
1060 // Possibly has a 'download' attribute for the anchor.
1061 if (file_name.empty())
1062 file_name = suggested_filename_;
1063 // From the URL file name.
1064 if (file_name.empty())
1065 file_name = GetURL().ExtractFileName();
1066 }
1067
[email protected]3d95e542012-11-20 00:52:081068 base::Callback<base::Value*(net::NetLog::LogLevel)> active_data = base::Bind(
1069 &ItemActivatedNetLogCallback, this, download_type, &file_name);
1070 if (active) {
1071 bound_net_log_.BeginEvent(
1072 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
1073 } else {
[email protected]4d4c5222012-09-06 19:29:221074 bound_net_log_.AddEvent(
[email protected]3d95e542012-11-20 00:52:081075 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
[email protected]4d4c5222012-09-06 19:29:221076 }
1077
1078 VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
1079}
1080
[email protected]53ac00e82012-10-18 20:59:201081// We're starting the download.
[email protected]8d68a3e02013-01-12 15:57:101082void DownloadItemImpl::Start(
1083 scoped_ptr<DownloadFile> file,
1084 scoped_ptr<DownloadRequestHandleInterface> req_handle) {
1085 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]53ac00e82012-10-18 20:59:201086 DCHECK(!download_file_.get());
1087 DCHECK(file.get());
[email protected]8d68a3e02013-01-12 15:57:101088 DCHECK(req_handle.get());
1089
[email protected]53ac00e82012-10-18 20:59:201090 download_file_ = file.Pass();
[email protected]8d68a3e02013-01-12 15:57:101091 request_handle_ = req_handle.Pass();
1092
1093 TransitionTo(IN_PROGRESS_INTERNAL);
1094
1095 last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
[email protected]53ac00e82012-10-18 20:59:201096
1097 BrowserThread::PostTask(
1098 BrowserThread::FILE, FROM_HERE,
1099 base::Bind(&DownloadFile::Initialize,
1100 // Safe because we control download file lifetime.
1101 base::Unretained(download_file_.get()),
1102 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
1103 weak_ptr_factory_.GetWeakPtr())));
1104}
1105
1106void DownloadItemImpl::OnDownloadFileInitialized(
[email protected]35869622012-10-26 23:23:551107 DownloadInterruptReason result) {
[email protected]8d68a3e02013-01-12 15:57:101108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]35869622012-10-26 23:23:551109 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
[email protected]53ac00e82012-10-18 20:59:201110 Interrupt(result);
1111 // TODO(rdsmith): It makes no sense to continue along the
1112 // regular download path after we've gotten an error. But it's
1113 // the way the code has historically worked, and this allows us
1114 // to get the download persisted and observers of the download manager
1115 // notified, so tests work. When we execute all side effects of cancel
[email protected]8d68a3e02013-01-12 15:57:101116 // (including queue removal) immediately rather than waiting for
[email protected]53ac00e82012-10-18 20:59:201117 // persistence we should replace this comment with a "return;".
1118 }
1119
[email protected]8d68a3e02013-01-12 15:57:101120 // If we're resuming an interrupted download, we may already know
1121 // the download target so we can skip target name determination.
1122 if (!GetTargetFilePath().empty() && !GetFullPath().empty()) {
1123 delegate_->ShowDownloadInBrowser(this);
1124 MaybeCompleteDownload();
1125 return;
1126 }
1127
1128 // The target path might be set and the full path empty if we failed
1129 // the intermediate rename--re-do file name determination in this case.
1130 // TODO(rdsmith,asanka): Clean up this logic.
1131 target_path_ = FilePath();
1132
[email protected]53ac00e82012-10-18 20:59:201133 delegate_->DetermineDownloadTarget(
1134 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
1135 weak_ptr_factory_.GetWeakPtr()));
1136}
1137
1138// Called by delegate_ when the download target path has been
[email protected]4d4c5222012-09-06 19:29:221139// determined.
1140void DownloadItemImpl::OnDownloadTargetDetermined(
1141 const FilePath& target_path,
1142 TargetDisposition disposition,
[email protected]35869622012-10-26 23:23:551143 DownloadDangerType danger_type,
[email protected]4d4c5222012-09-06 19:29:221144 const FilePath& intermediate_path) {
1145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1146
1147 // If the |target_path| is empty, then we consider this download to be
1148 // canceled.
1149 if (target_path.empty()) {
1150 Cancel(true);
1151 return;
1152 }
1153
[email protected]8d68a3e02013-01-12 15:57:101154 // TODO(rdsmith,asanka): We are ignoring the possibility that the download
1155 // has been interrupted at this point until we finish the intermediate
1156 // rename and set the full path. That's dangerous, because we might race
1157 // with resumption, either manual (because the interrupt is visible to the
1158 // UI) or automatic. If we keep the "ignore an error on download until file
1159 // name determination complete" semantics, we need to make sure that the
1160 // error is kept completely invisible until that point.
1161
[email protected]3d95e542012-11-20 00:52:081162 VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
1163 << " " << danger_type << " " << DebugString(true);
1164
[email protected]4d4c5222012-09-06 19:29:221165 target_path_ = target_path;
1166 target_disposition_ = disposition;
1167 SetDangerType(danger_type);
1168 // TODO(asanka): SetDangerType() doesn't need to send a notification here.
1169
1170 // We want the intermediate and target paths to refer to the same directory so
1171 // that they are both on the same device and subject to same
1172 // space/permission/availability constraints.
1173 DCHECK(intermediate_path.DirName() == target_path.DirName());
1174
1175 // Rename to intermediate name.
1176 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
1177 // spurious rename when we can just rename to the final
1178 // filename. Unnecessary renames may cause bugs like
1179 // http://crbug.com/74187.
[email protected]53ac00e82012-10-18 20:59:201180 DCHECK(!is_save_package_download_);
[email protected]dd7ef802012-10-25 20:59:241181 DCHECK(download_file_.get());
[email protected]53ac00e82012-10-18 20:59:201182 DownloadFile::RenameCompletionCallback callback =
[email protected]4d4c5222012-09-06 19:29:221183 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
1184 weak_ptr_factory_.GetWeakPtr());
1185 BrowserThread::PostTask(
1186 BrowserThread::FILE, FROM_HERE,
[email protected]d6825972012-11-10 01:22:521187 base::Bind(&DownloadFile::RenameAndUniquify,
[email protected]53ac00e82012-10-18 20:59:201188 // Safe because we control download file lifetime.
1189 base::Unretained(download_file_.get()),
[email protected]d6825972012-11-10 01:22:521190 intermediate_path, callback));
[email protected]4d4c5222012-09-06 19:29:221191}
1192
1193void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
[email protected]35869622012-10-26 23:23:551194 DownloadInterruptReason reason,
[email protected]4d4c5222012-09-06 19:29:221195 const FilePath& full_path) {
1196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d95e542012-11-20 00:52:081197 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]5fb71452012-12-11 21:37:221198 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason)
[email protected]4d4c5222012-09-06 19:29:221199 Interrupt(reason);
[email protected]5fb71452012-12-11 21:37:221200 else
[email protected]4d4c5222012-09-06 19:29:221201 SetFullPath(full_path);
[email protected]5fb71452012-12-11 21:37:221202 delegate_->ShowDownloadInBrowser(this);
[email protected]4d4c5222012-09-06 19:29:221203
[email protected]3d95e542012-11-20 00:52:081204 MaybeCompleteDownload();
[email protected]c09a8fd2011-11-21 19:54:501205}
1206
[email protected]18710a42a2012-10-17 19:50:431207// When SavePackage downloads MHTML to GData (see
1208// SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
1209// does for non-SavePackage downloads, but SavePackage downloads never satisfy
1210// IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
1211// DownloadItem::UpdateObservers() when the upload completes so that SavePackage
1212// notices that the upload has completed and runs its normal Finish() pathway.
1213// MaybeCompleteDownload() is never the mechanism by which SavePackage completes
1214// downloads. SavePackage always uses its own Finish() to mark downloads
1215// complete.
[email protected]fc03de22011-12-06 23:28:121216void DownloadItemImpl::MaybeCompleteDownload() {
[email protected]18710a42a2012-10-17 19:50:431217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d6825972012-11-10 01:22:521218 DCHECK(!is_save_package_download_);
[email protected]18710a42a2012-10-17 19:50:431219
[email protected]98299622013-01-03 22:26:501220 if (!IsDownloadReadyForCompletion(
1221 base::Bind(&DownloadItemImpl::MaybeCompleteDownload,
1222 weak_ptr_factory_.GetWeakPtr())))
[email protected]18710a42a2012-10-17 19:50:431223 return;
1224
1225 // TODO(rdsmith): DCHECK that we only pass through this point
1226 // once per download. The natural way to do this is by a state
1227 // transition on the DownloadItem.
1228
1229 // Confirm we're in the proper set of states to be here;
1230 // have all data, have a history handle, (validated or safe).
1231 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
[email protected]cda79062013-01-17 01:50:521232 DCHECK(!IsDangerous());
[email protected]18710a42a2012-10-17 19:50:431233 DCHECK(all_data_saved_);
[email protected]18710a42a2012-10-17 19:50:431234
1235 OnDownloadCompleting();
[email protected]fc03de22011-12-06 23:28:121236}
1237
[email protected]18710a42a2012-10-17 19:50:431238// Called by MaybeCompleteDownload() when it has determined that the download
1239// is ready for completion.
[email protected]4d4c5222012-09-06 19:29:221240void DownloadItemImpl::OnDownloadCompleting() {
1241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1242
[email protected]d0d368252012-09-24 17:13:421243 if (state_ != IN_PROGRESS_INTERNAL)
1244 return;
1245
[email protected]4d4c5222012-09-06 19:29:221246 VLOG(20) << __FUNCTION__ << "()"
[email protected]4d4c5222012-09-06 19:29:221247 << " " << DebugString(true);
[email protected]e9e6b122012-09-12 19:21:451248 DCHECK(!GetTargetFilePath().empty());
[email protected]cda79062013-01-17 01:50:521249 DCHECK(!IsDangerous());
[email protected]4d4c5222012-09-06 19:29:221250
[email protected]53ac00e82012-10-18 20:59:201251 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
1252 if (is_save_package_download_) {
1253 // Avoid doing anything on the file thread; there's nothing we control
1254 // there.
[email protected]d6825972012-11-10 01:22:521255 // Strictly speaking, this skips giving the embedder a chance to open
1256 // the download. But on a save package download, there's no real
1257 // concept of opening.
1258 Completed();
[email protected]53ac00e82012-10-18 20:59:201259 return;
1260 }
1261
[email protected]dd7ef802012-10-25 20:59:241262 DCHECK(download_file_.get());
[email protected]d6825972012-11-10 01:22:521263 // Unilaterally rename; even if it already has the right name,
1264 // we need theannotation.
1265 DownloadFile::RenameCompletionCallback callback =
1266 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName,
1267 weak_ptr_factory_.GetWeakPtr());
1268 BrowserThread::PostTask(
1269 BrowserThread::FILE, FROM_HERE,
1270 base::Bind(&DownloadFile::RenameAndAnnotate,
1271 base::Unretained(download_file_.get()),
1272 GetTargetFilePath(), callback));
[email protected]4d4c5222012-09-06 19:29:221273}
1274
1275void DownloadItemImpl::OnDownloadRenamedToFinalName(
[email protected]35869622012-10-26 23:23:551276 DownloadInterruptReason reason,
[email protected]4d4c5222012-09-06 19:29:221277 const FilePath& full_path) {
1278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d6825972012-11-10 01:22:521279 DCHECK(!is_save_package_download_);
[email protected]4d4c5222012-09-06 19:29:221280
[email protected]d0d368252012-09-24 17:13:421281 // If a cancel or interrupt hit, we'll cancel the DownloadFile, which
1282 // will result in deleting the file on the file thread. So we don't
1283 // care about the name having been changed.
1284 if (state_ != IN_PROGRESS_INTERNAL)
1285 return;
1286
[email protected]4d4c5222012-09-06 19:29:221287 VLOG(20) << __FUNCTION__ << "()"
1288 << " full_path = \"" << full_path.value() << "\""
[email protected]4d4c5222012-09-06 19:29:221289 << " " << DebugString(false);
[email protected]4d4c5222012-09-06 19:29:221290
[email protected]35869622012-10-26 23:23:551291 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
[email protected]4d4c5222012-09-06 19:29:221292 Interrupt(reason);
1293 return;
1294 }
1295
[email protected]d6825972012-11-10 01:22:521296 DCHECK(target_path_ == full_path);
[email protected]4d4c5222012-09-06 19:29:221297
[email protected]d6825972012-11-10 01:22:521298 if (full_path != current_path_) {
1299 // full_path is now the current and target file path.
1300 DCHECK(!full_path.empty());
1301 SetFullPath(full_path);
[email protected]d6825972012-11-10 01:22:521302 }
[email protected]53ac00e82012-10-18 20:59:201303
[email protected]4d4c5222012-09-06 19:29:221304 // Complete the download and release the DownloadFile.
[email protected]dd7ef802012-10-25 20:59:241305 DCHECK(download_file_.get());
[email protected]4d4c5222012-09-06 19:29:221306 BrowserThread::PostTask(
1307 BrowserThread::FILE, FROM_HERE,
[email protected]c7e946702012-12-18 11:55:091308 base::Bind(&DownloadFileDetach, base::Passed(&download_file_)));
[email protected]53ac00e82012-10-18 20:59:201309
1310 // We're not completely done with the download item yet, but at this
1311 // point we're committed to complete the download. Cancels (or Interrupts,
1312 // though it's not clear how they could happen) after this point will be
1313 // ignored.
[email protected]d0d368252012-09-24 17:13:421314 TransitionTo(COMPLETING_INTERNAL);
[email protected]4d4c5222012-09-06 19:29:221315
[email protected]bde0e4f2012-11-08 22:49:591316 if (delegate_->ShouldOpenDownload(
1317 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened,
1318 weak_ptr_factory_.GetWeakPtr()))) {
[email protected]4d4c5222012-09-06 19:29:221319 Completed();
[email protected]bde0e4f2012-11-08 22:49:591320 } else {
[email protected]4d4c5222012-09-06 19:29:221321 delegate_delayed_complete_ = true;
[email protected]bde0e4f2012-11-08 22:49:591322 }
[email protected]4d4c5222012-09-06 19:29:221323}
1324
1325void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
[email protected]8d68a3e02013-01-12 15:57:101326 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1327
[email protected]4d4c5222012-09-06 19:29:221328 auto_opened_ = auto_opened;
1329 Completed();
1330}
1331
[email protected]c09a8fd2011-11-21 19:54:501332void DownloadItemImpl::Completed() {
[email protected]0634626a2012-05-03 19:04:261333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:501334
1335 VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
1336
[email protected]336721e2012-06-29 08:09:381337 DCHECK(all_data_saved_);
1338 end_time_ = base::Time::Now();
[email protected]d0d368252012-09-24 17:13:421339 TransitionTo(COMPLETE_INTERNAL);
[email protected]35869622012-10-26 23:23:551340 RecordDownloadCompleted(start_tick_, received_bytes_);
[email protected]336721e2012-06-29 08:09:381341
[email protected]c09a8fd2011-11-21 19:54:501342 if (auto_opened_) {
1343 // If it was already handled by the delegate, do nothing.
1344 } else if (GetOpenWhenComplete() ||
1345 ShouldOpenFileBasedOnExtension() ||
1346 IsTemporary()) {
1347 // If the download is temporary, like in drag-and-drop, do not open it but
1348 // we still need to set it auto-opened so that it can be removed from the
1349 // download shelf.
1350 if (!IsTemporary())
1351 OpenDownload();
1352
1353 auto_opened_ = true;
1354 UpdateObservers();
1355 }
1356}
1357
[email protected]4d4c5222012-09-06 19:29:221358// **** End of Download progression cascade
1359
[email protected]bde0e4f2012-11-08 22:49:591360// An error occurred somewhere.
1361void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
[email protected]8d68a3e02013-01-12 15:57:101362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1363
[email protected]bde0e4f2012-11-08 22:49:591364 // Somewhat counter-intuitively, it is possible for us to receive an
1365 // interrupt after we've already been interrupted. The generation of
1366 // interrupts from the file thread Renames and the generation of
1367 // interrupts from disk writes go through two different mechanisms (driven
1368 // by rename requests from UI thread and by write requests from IO thread,
1369 // respectively), and since we choose not to keep state on the File thread,
1370 // this is the place where the races collide. It's also possible for
1371 // interrupts to race with cancels.
1372
1373 // Whatever happens, the first one to hit the UI thread wins.
[email protected]d6825972012-11-10 01:22:521374 if (state_ != IN_PROGRESS_INTERNAL)
[email protected]bde0e4f2012-11-08 22:49:591375 return;
1376
1377 last_reason_ = reason;
[email protected]8d68a3e02013-01-12 15:57:101378
[email protected]bde0e4f2012-11-08 22:49:591379 TransitionTo(INTERRUPTED_INTERNAL);
1380
[email protected]8d68a3e02013-01-12 15:57:101381 ResumeMode resume_mode = GetResumeMode();
1382 if (resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
1383 resume_mode == RESUME_MODE_USER_RESTART) {
1384 // Remove the download file; no point in leaving data around we
1385 // aren't going to use.
1386 CancelDownloadFile();
1387 } else {
1388 // Keep the file around and maybe re-use it.
1389 BrowserThread::PostTask(
1390 BrowserThread::FILE, FROM_HERE,
1391 base::Bind(&DownloadFileDetach, base::Passed(&download_file_)));
1392 }
[email protected]bde0e4f2012-11-08 22:49:591393
1394 // Cancel the originating URL request.
1395 request_handle_->CancelRequest();
1396
1397 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
[email protected]8d68a3e02013-01-12 15:57:101398 AutoResumeIfValid();
[email protected]bde0e4f2012-11-08 22:49:591399}
1400
[email protected]53ac00e82012-10-18 20:59:201401void DownloadItemImpl::CancelDownloadFile() {
[email protected]8d68a3e02013-01-12 15:57:101402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1403
[email protected]53ac00e82012-10-18 20:59:201404 // TODO(rdsmith/benjhayden): Remove condition as part of
[email protected]8d68a3e02013-01-12 15:57:101405 // |SavePackage| integration.
1406 // |download_file_| can be NULL if Interrupt() is called after the
1407 // download file has been released.
[email protected]0e13f5c2012-10-29 13:24:061408 if (!is_save_package_download_ && download_file_.get()) {
[email protected]53ac00e82012-10-18 20:59:201409 BrowserThread::PostTask(
1410 BrowserThread::FILE, FROM_HERE,
1411 // Will be deleted at end of task execution.
[email protected]c7e946702012-12-18 11:55:091412 base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
[email protected]53ac00e82012-10-18 20:59:201413 }
1414}
1415
[email protected]98299622013-01-03 22:26:501416bool DownloadItemImpl::IsDownloadReadyForCompletion(
1417 const base::Closure& state_change_notification) {
[email protected]18710a42a2012-10-17 19:50:431418 // If we don't have all the data, the download is not ready for
1419 // completion.
1420 if (!AllDataSaved())
1421 return false;
1422
1423 // If the download is dangerous, but not yet validated, it's not ready for
1424 // completion.
[email protected]cda79062013-01-17 01:50:521425 if (IsDangerous())
[email protected]18710a42a2012-10-17 19:50:431426 return false;
1427
1428 // If the download isn't active (e.g. has been cancelled) it's not
1429 // ready for completion.
1430 if (state_ != IN_PROGRESS_INTERNAL)
1431 return false;
1432
[email protected]3d95e542012-11-20 00:52:081433 // If the target filename hasn't been determined, then it's not ready for
1434 // completion. This is checked in ReadyForDownloadCompletionDone().
1435 if (GetTargetFilePath().empty())
1436 return false;
1437
1438 // This is checked in NeedsRename(). Without this conditional,
1439 // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK.
1440 if (target_path_.DirName() != current_path_.DirName())
[email protected]18710a42a2012-10-17 19:50:431441 return false;
1442
[email protected]98299622013-01-03 22:26:501443 // Give the delegate a chance to hold up a stop sign. It'll call
1444 // use back through the passed callback if it does and that state changes.
1445 if (!delegate_->ShouldCompleteDownload(this, state_change_notification))
1446 return false;
1447
[email protected]18710a42a2012-10-17 19:50:431448 return true;
1449}
1450
[email protected]d0d368252012-09-24 17:13:421451void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
[email protected]8d68a3e02013-01-12 15:57:101452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1453
[email protected]c09a8fd2011-11-21 19:54:501454 if (state_ == new_state)
1455 return;
1456
[email protected]d0d368252012-09-24 17:13:421457 DownloadInternalState old_state = state_;
[email protected]c09a8fd2011-11-21 19:54:501458 state_ = new_state;
[email protected]a6e12012012-02-08 02:24:081459
1460 switch (state_) {
[email protected]d0d368252012-09-24 17:13:421461 case COMPLETING_INTERNAL:
1462 bound_net_log_.AddEvent(
1463 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
[email protected]35869622012-10-26 23:23:551464 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
[email protected]d0d368252012-09-24 17:13:421465 break;
1466 case COMPLETE_INTERNAL:
[email protected]a6e12012012-02-08 02:24:081467 bound_net_log_.AddEvent(
1468 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
[email protected]35869622012-10-26 23:23:551469 base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
[email protected]a6e12012012-02-08 02:24:081470 break;
[email protected]d0d368252012-09-24 17:13:421471 case INTERRUPTED_INTERNAL:
[email protected]a6e12012012-02-08 02:24:081472 bound_net_log_.AddEvent(
1473 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
[email protected]35869622012-10-26 23:23:551474 base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
1475 received_bytes_, &hash_state_));
[email protected]a6e12012012-02-08 02:24:081476 break;
[email protected]8d68a3e02013-01-12 15:57:101477 case IN_PROGRESS_INTERNAL:
1478 if (old_state == INTERRUPTED_INTERNAL) {
1479 bound_net_log_.AddEvent(
1480 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
1481 base::Bind(&ItemResumingNetLogCallback,
1482 false, last_reason_, received_bytes_, &hash_state_));
1483 }
1484 break;
[email protected]d0d368252012-09-24 17:13:421485 case CANCELLED_INTERNAL:
[email protected]a6e12012012-02-08 02:24:081486 bound_net_log_.AddEvent(
1487 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
[email protected]35869622012-10-26 23:23:551488 base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
1489 &hash_state_));
[email protected]a6e12012012-02-08 02:24:081490 break;
1491 default:
1492 break;
1493 }
1494
[email protected]3d95e542012-11-20 00:52:081495 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
1496 << " " << InternalToExternalState(old_state)
1497 << " " << InternalToExternalState(state_);
[email protected]1138ff02012-03-14 21:14:281498
[email protected]d0d368252012-09-24 17:13:421499 // Only update observers on user visible state changes.
[email protected]8d68a3e02013-01-12 15:57:101500 if (InternalToExternalState(state_) != InternalToExternalState(old_state))
[email protected]d0d368252012-09-24 17:13:421501 UpdateObservers();
[email protected]a6e12012012-02-08 02:24:081502
[email protected]d0d368252012-09-24 17:13:421503 bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
1504 state_ != COMPLETING_INTERNAL);
1505 bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
1506 old_state != COMPLETING_INTERNAL);
[email protected]8d68a3e02013-01-12 15:57:101507 // Termination
[email protected]a6e12012012-02-08 02:24:081508 if (is_done && !was_done)
[email protected]2fa08912012-06-14 20:56:261509 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
[email protected]8d68a3e02013-01-12 15:57:101510
1511 // Resumption
1512 if (was_done && !is_done) {
1513 std::string file_name(target_path_.BaseName().AsUTF8Unsafe());
1514 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
1515 base::Bind(&ItemActivatedNetLogCallback,
1516 this, SRC_ACTIVE_DOWNLOAD,
1517 &file_name));
1518 }
[email protected]c09a8fd2011-11-21 19:54:501519}
1520
[email protected]35869622012-10-26 23:23:551521void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
[email protected]cda79062013-01-17 01:50:521522 if (danger_type != danger_type_) {
[email protected]a6e12012012-02-08 02:24:081523 bound_net_log_.AddEvent(
1524 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
[email protected]cda79062013-01-17 01:50:521525 base::Bind(&ItemCheckedNetLogCallback, danger_type));
[email protected]c09a8fd2011-11-21 19:54:501526 }
[email protected]cda79062013-01-17 01:50:521527 danger_type_ = danger_type;
[email protected]c09a8fd2011-11-21 19:54:501528}
1529
[email protected]3d833de2012-05-30 23:32:061530void DownloadItemImpl::SetFullPath(const FilePath& new_path) {
[email protected]0634626a2012-05-03 19:04:261531 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d833de2012-05-30 23:32:061532 VLOG(20) << __FUNCTION__ << "()"
1533 << " new_path = \"" << new_path.value() << "\""
1534 << " " << DebugString(true);
1535 DCHECK(!new_path.empty());
[email protected]c09a8fd2011-11-21 19:54:501536
[email protected]3d833de2012-05-30 23:32:061537 bound_net_log_.AddEvent(
1538 net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED,
[email protected]35869622012-10-26 23:23:551539 base::Bind(&ItemRenamedNetLogCallback, &current_path_, &new_path));
[email protected]6313d142012-11-26 23:13:421540
1541 current_path_ = new_path;
1542 UpdateObservers();
[email protected]c09a8fd2011-11-21 19:54:501543}
1544
[email protected]8d68a3e02013-01-12 15:57:101545void DownloadItemImpl::AutoResumeIfValid() {
1546 DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
1547 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1548 ResumeMode mode = GetResumeMode();
1549
1550 if (mode != RESUME_MODE_IMMEDIATE_RESTART &&
1551 mode != RESUME_MODE_IMMEDIATE_CONTINUE) {
1552 return;
1553 }
1554
1555 auto_resume_count_++;
1556
1557 ResumeInterruptedDownload();
1558}
1559
[email protected]d0d368252012-09-24 17:13:421560// static
1561DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
1562 DownloadInternalState internal_state) {
1563 switch (internal_state) {
1564 case IN_PROGRESS_INTERNAL:
1565 return IN_PROGRESS;
1566 case COMPLETING_INTERNAL:
1567 return IN_PROGRESS;
1568 case COMPLETE_INTERNAL:
1569 return COMPLETE;
1570 case CANCELLED_INTERNAL:
1571 return CANCELLED;
1572 case INTERRUPTED_INTERNAL:
1573 return INTERRUPTED;
1574 default:
1575 NOTREACHED();
1576 }
1577 return MAX_DOWNLOAD_STATE;
1578}
[email protected]5009b7a2012-02-21 18:47:031579
[email protected]d0d368252012-09-24 17:13:421580// static
1581DownloadItemImpl::DownloadInternalState
1582DownloadItemImpl::ExternalToInternalState(
1583 DownloadState external_state) {
1584 switch (external_state) {
1585 case IN_PROGRESS:
1586 return IN_PROGRESS_INTERNAL;
1587 case COMPLETE:
1588 return COMPLETE_INTERNAL;
1589 case CANCELLED:
1590 return CANCELLED_INTERNAL;
1591 case INTERRUPTED:
1592 return INTERRUPTED_INTERNAL;
1593 default:
1594 NOTREACHED();
1595 }
1596 return MAX_DOWNLOAD_INTERNAL_STATE;
1597 }
[email protected]a6e12012012-02-08 02:24:081598
[email protected]d0d368252012-09-24 17:13:421599const char* DownloadItemImpl::DebugDownloadStateString(
1600 DownloadInternalState state) {
1601 switch (state) {
1602 case IN_PROGRESS_INTERNAL:
1603 return "IN_PROGRESS";
1604 case COMPLETING_INTERNAL:
1605 return "COMPLETING";
1606 case COMPLETE_INTERNAL:
1607 return "COMPLETE";
1608 case CANCELLED_INTERNAL:
1609 return "CANCELLED";
1610 case INTERRUPTED_INTERNAL:
1611 return "INTERRUPTED";
1612 default:
1613 NOTREACHED() << "Unknown download state " << state;
1614 return "unknown";
1615 };
1616}
[email protected]35869622012-10-26 23:23:551617
[email protected]8d68a3e02013-01-12 15:57:101618const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
1619 switch (mode) {
1620 case RESUME_MODE_INVALID:
1621 return "INVALID";
1622 case RESUME_MODE_IMMEDIATE_CONTINUE:
1623 return "IMMEDIATE_CONTINUE";
1624 case RESUME_MODE_IMMEDIATE_RESTART:
1625 return "IMMEDIATE_RESTART";
1626 case RESUME_MODE_USER_CONTINUE:
1627 return "USER_CONTINUE";
1628 case RESUME_MODE_USER_RESTART:
1629 return "USER_RESTART";
1630 }
1631 NOTREACHED() << "Unknown resume mode " << mode;
1632 return "unknown";
1633}
1634
[email protected]35869622012-10-26 23:23:551635} // namespace content