blob: 1e51cd02c986e5f3248335974f50a88248892277 [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"
30#include "base/file_util.h"
31#include "base/format_macros.h"
[email protected]c09a8fd2011-11-21 19:54:5032#include "base/logging.h"
33#include "base/metrics/histogram.h"
[email protected]5bcef5c72011-12-07 23:03:2434#include "base/stl_util.h"
[email protected]c09a8fd2011-11-21 19:54:5035#include "base/stringprintf.h"
36#include "base/utf_string_conversions.h"
37#include "content/browser/download/download_create_info.h"
[email protected]f363dae2012-01-31 06:08:2338#include "content/browser/download/download_file.h"
[email protected]bf3b08a2012-03-08 01:52:3439#include "content/browser/download/download_interrupt_reasons_impl.h"
[email protected]db1d8f72012-07-13 19:23:1640#include "content/browser/download/download_item_impl_delegate.h"
[email protected]c09a8fd2011-11-21 19:54:5041#include "content/browser/download/download_request_handle.h"
42#include "content/browser/download/download_stats.h"
[email protected]93ddb3c2012-04-11 21:44:2943#include "content/browser/web_contents/web_contents_impl.h"
[email protected]c09a8fd2011-11-21 19:54:5044#include "content/public/browser/browser_thread.h"
45#include "content/public/browser/content_browser_client.h"
[email protected]c09a8fd2011-11-21 19:54:5046#include "net/base/net_util.h"
47
[email protected]35869622012-10-26 23:23:5548namespace content {
[email protected]c09a8fd2011-11-21 19:54:5049namespace {
50
51static void DeleteDownloadedFile(const FilePath& path) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
53
54 // Make sure we only delete files.
55 if (!file_util::DirectoryExists(path))
56 file_util::Delete(path, false);
57}
58
59const char* DebugSafetyStateString(DownloadItem::SafetyState state) {
60 switch (state) {
61 case DownloadItem::SAFE:
62 return "SAFE";
63 case DownloadItem::DANGEROUS:
64 return "DANGEROUS";
65 case DownloadItem::DANGEROUS_BUT_VALIDATED:
66 return "DANGEROUS_BUT_VALIDATED";
67 default:
68 NOTREACHED() << "Unknown safety state " << state;
69 return "unknown";
70 };
71}
72
[email protected]c09a8fd2011-11-21 19:54:5073// Classes to null out request handle calls (for SavePage DownloadItems, which
74// may have, e.g., Cancel() called on them without it doing anything)
75// and to DCHECK on them (for history DownloadItems, which should never have
76// any operation that implies an off-thread component, since they don't
77// have any).
78class NullDownloadRequestHandle : public DownloadRequestHandleInterface {
79 public:
80 NullDownloadRequestHandle() {}
81
82 // DownloadRequestHandleInterface calls
[email protected]b172aee2012-04-10 17:05:2683 virtual WebContents* GetWebContents() const OVERRIDE {
[email protected]c09a8fd2011-11-21 19:54:5084 return NULL;
85 }
86 virtual DownloadManager* GetDownloadManager() const OVERRIDE {
87 return NULL;
88 }
89 virtual void PauseRequest() const OVERRIDE {}
90 virtual void ResumeRequest() const OVERRIDE {}
91 virtual void CancelRequest() const OVERRIDE {}
92 virtual std::string DebugString() const OVERRIDE {
93 return "Null DownloadRequestHandle";
94 }
95};
96
[email protected]53ac00e82012-10-18 20:59:2097// Wrapper around DownloadFile::Detach and DownloadFile::Cancel that
98// takes ownership of the DownloadFile and hence implicitly destroys it
99// at the end of the function.
[email protected]d6825972012-11-10 01:22:52100static void DownloadFileDetach(scoped_ptr<DownloadFile> download_file) {
[email protected]53ac00e82012-10-18 20:59:20101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]d6825972012-11-10 01:22:52102 download_file->Detach();
[email protected]53ac00e82012-10-18 20:59:20103}
104
105static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
107 download_file->Cancel();
108}
109
[email protected]c09a8fd2011-11-21 19:54:50110} // namespace
111
[email protected]e582fdd2011-12-20 16:48:17112const char DownloadItem::kEmptyFileHash[] = "";
113
[email protected]c09a8fd2011-11-21 19:54:50114// Constructor for reading from the history service.
[email protected]db1d8f72012-07-13 19:23:16115DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
[email protected]fc03de22011-12-06 23:28:12116 DownloadId download_id,
[email protected]3d95e542012-11-20 00:52:08117 const FilePath& path,
118 const GURL& url,
119 const GURL& referrer_url,
120 const base::Time& start_time,
121 const base::Time& end_time,
122 int64 received_bytes,
123 int64 total_bytes,
124 DownloadItem::DownloadState state,
125 bool opened,
[email protected]a6e12012012-02-08 02:24:08126 const net::BoundNetLog& bound_net_log)
[email protected]53ac00e82012-10-18 20:59:20127 : is_save_package_download_(false),
128 download_id_(download_id),
[email protected]3d95e542012-11-20 00:52:08129 current_path_(path),
130 target_path_(path),
[email protected]3d833de2012-05-30 23:32:06131 target_disposition_(TARGET_DISPOSITION_OVERWRITE),
[email protected]3d95e542012-11-20 00:52:08132 url_chain_(1, url),
133 referrer_url_(referrer_url),
[email protected]35869622012-10-26 23:23:55134 transition_type_(PAGE_TRANSITION_LINK),
[email protected]3d833de2012-05-30 23:32:06135 has_user_gesture_(false),
[email protected]3d95e542012-11-20 00:52:08136 total_bytes_(total_bytes),
137 received_bytes_(received_bytes),
[email protected]e384fd82011-11-30 06:37:20138 bytes_per_sec_(0),
[email protected]35869622012-10-26 23:23:55139 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
[email protected]c09a8fd2011-11-21 19:54:50140 start_tick_(base::TimeTicks()),
[email protected]3d95e542012-11-20 00:52:08141 state_(ExternalToInternalState(state)),
[email protected]35869622012-10-26 23:23:55142 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
[email protected]3d95e542012-11-20 00:52:08143 start_time_(start_time),
144 end_time_(end_time),
[email protected]fc03de22011-12-06 23:28:12145 delegate_(delegate),
[email protected]c09a8fd2011-11-21 19:54:50146 is_paused_(false),
147 open_when_complete_(false),
148 file_externally_removed_(false),
149 safety_state_(SAFE),
150 auto_opened_(false),
[email protected]c09a8fd2011-11-21 19:54:50151 is_temporary_(false),
152 all_data_saved_(false),
[email protected]3d95e542012-11-20 00:52:08153 opened_(opened),
[email protected]c09a8fd2011-11-21 19:54:50154 open_enabled_(true),
[email protected]a6e12012012-02-08 02:24:08155 delegate_delayed_complete_(false),
[email protected]3d833de2012-05-30 23:32:06156 bound_net_log_(bound_net_log),
157 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]fc03de22011-12-06 23:28:12158 delegate_->Attach();
[email protected]d0d368252012-09-24 17:13:42159 if (state_ == IN_PROGRESS_INTERNAL)
160 state_ = CANCELLED_INTERNAL;
161 if (state_ == COMPLETE_INTERNAL)
[email protected]c09a8fd2011-11-21 19:54:50162 all_data_saved_ = true;
[email protected]35869622012-10-26 23:23:55163 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
[email protected]c09a8fd2011-11-21 19:54:50164}
165
166// Constructing for a regular download:
167DownloadItemImpl::DownloadItemImpl(
[email protected]db1d8f72012-07-13 19:23:16168 DownloadItemImplDelegate* delegate,
[email protected]c09a8fd2011-11-21 19:54:50169 const DownloadCreateInfo& info,
[email protected]94d841cf2012-06-12 20:58:20170 scoped_ptr<DownloadRequestHandleInterface> request_handle,
[email protected]a6e12012012-02-08 02:24:08171 const net::BoundNetLog& bound_net_log)
[email protected]53ac00e82012-10-18 20:59:20172 : is_save_package_download_(false),
173 request_handle_(request_handle.Pass()),
[email protected]c09a8fd2011-11-21 19:54:50174 download_id_(info.download_id),
[email protected]3d833de2012-05-30 23:32:06175 target_disposition_(
[email protected]3a2b2b5c2012-11-01 23:55:30176 (info.save_info->prompt_for_save_location) ?
[email protected]3d833de2012-05-30 23:32:06177 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE),
[email protected]c09a8fd2011-11-21 19:54:50178 url_chain_(info.url_chain),
179 referrer_url_(info.referrer_url),
[email protected]c873c862012-10-17 15:32:12180 suggested_filename_(UTF16ToUTF8(info.save_info->suggested_name)),
181 forced_file_path_(info.save_info->file_path),
[email protected]3d833de2012-05-30 23:32:06182 transition_type_(info.transition_type),
183 has_user_gesture_(info.has_user_gesture),
[email protected]c09a8fd2011-11-21 19:54:50184 content_disposition_(info.content_disposition),
185 mime_type_(info.mime_type),
186 original_mime_type_(info.original_mime_type),
[email protected]28aa2ed2011-12-06 06:27:38187 remote_address_(info.remote_address),
[email protected]c09a8fd2011-11-21 19:54:50188 total_bytes_(info.total_bytes),
189 received_bytes_(0),
[email protected]e384fd82011-11-30 06:37:20190 bytes_per_sec_(0),
[email protected]35869622012-10-26 23:23:55191 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
[email protected]c09a8fd2011-11-21 19:54:50192 start_tick_(base::TimeTicks::Now()),
[email protected]d0d368252012-09-24 17:13:42193 state_(IN_PROGRESS_INTERNAL),
[email protected]35869622012-10-26 23:23:55194 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
[email protected]c09a8fd2011-11-21 19:54:50195 start_time_(info.start_time),
[email protected]fc03de22011-12-06 23:28:12196 delegate_(delegate),
[email protected]c09a8fd2011-11-21 19:54:50197 is_paused_(false),
198 open_when_complete_(false),
199 file_externally_removed_(false),
200 safety_state_(SAFE),
201 auto_opened_(false),
[email protected]c873c862012-10-17 15:32:12202 is_temporary_(!info.save_info->file_path.empty()),
[email protected]c09a8fd2011-11-21 19:54:50203 all_data_saved_(false),
204 opened_(false),
205 open_enabled_(true),
[email protected]a6e12012012-02-08 02:24:08206 delegate_delayed_complete_(false),
[email protected]3d833de2012-05-30 23:32:06207 bound_net_log_(bound_net_log),
208 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]fc03de22011-12-06 23:28:12209 delegate_->Attach();
[email protected]35869622012-10-26 23:23:55210 Init(true /* actively downloading */, SRC_NEW_DOWNLOAD);
[email protected]ef17c9a2012-02-09 05:08:09211
212 // Link the event sources.
213 bound_net_log_.AddEvent(
214 net::NetLog::TYPE_DOWNLOAD_URL_REQUEST,
[email protected]2fa08912012-06-14 20:56:26215 info.request_bound_net_log.source().ToEventParametersCallback());
[email protected]ef17c9a2012-02-09 05:08:09216
217 info.request_bound_net_log.AddEvent(
218 net::NetLog::TYPE_DOWNLOAD_STARTED,
[email protected]2fa08912012-06-14 20:56:26219 bound_net_log_.source().ToEventParametersCallback());
[email protected]c09a8fd2011-11-21 19:54:50220}
221
222// Constructing for the "Save Page As..." feature:
[email protected]db1d8f72012-07-13 19:23:16223DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
[email protected]c09a8fd2011-11-21 19:54:50224 const FilePath& path,
225 const GURL& url,
[email protected]a6e12012012-02-08 02:24:08226 DownloadId download_id,
[email protected]6474b112012-05-04 19:35:27227 const std::string& mime_type,
[email protected]a6e12012012-02-08 02:24:08228 const net::BoundNetLog& bound_net_log)
[email protected]53ac00e82012-10-18 20:59:20229 : is_save_package_download_(true),
230 request_handle_(new NullDownloadRequestHandle()),
[email protected]c09a8fd2011-11-21 19:54:50231 download_id_(download_id),
[email protected]3d833de2012-05-30 23:32:06232 current_path_(path),
233 target_path_(path),
234 target_disposition_(TARGET_DISPOSITION_OVERWRITE),
[email protected]c09a8fd2011-11-21 19:54:50235 url_chain_(1, url),
236 referrer_url_(GURL()),
[email protected]35869622012-10-26 23:23:55237 transition_type_(PAGE_TRANSITION_LINK),
[email protected]3d833de2012-05-30 23:32:06238 has_user_gesture_(false),
[email protected]6474b112012-05-04 19:35:27239 mime_type_(mime_type),
240 original_mime_type_(mime_type),
[email protected]c09a8fd2011-11-21 19:54:50241 total_bytes_(0),
242 received_bytes_(0),
[email protected]e384fd82011-11-30 06:37:20243 bytes_per_sec_(0),
[email protected]35869622012-10-26 23:23:55244 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
[email protected]c09a8fd2011-11-21 19:54:50245 start_tick_(base::TimeTicks::Now()),
[email protected]d0d368252012-09-24 17:13:42246 state_(IN_PROGRESS_INTERNAL),
[email protected]35869622012-10-26 23:23:55247 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
[email protected]c09a8fd2011-11-21 19:54:50248 start_time_(base::Time::Now()),
[email protected]fc03de22011-12-06 23:28:12249 delegate_(delegate),
[email protected]c09a8fd2011-11-21 19:54:50250 is_paused_(false),
251 open_when_complete_(false),
252 file_externally_removed_(false),
253 safety_state_(SAFE),
254 auto_opened_(false),
[email protected]c09a8fd2011-11-21 19:54:50255 is_temporary_(false),
256 all_data_saved_(false),
257 opened_(false),
258 open_enabled_(true),
[email protected]a6e12012012-02-08 02:24:08259 delegate_delayed_complete_(false),
[email protected]3d833de2012-05-30 23:32:06260 bound_net_log_(bound_net_log),
261 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]fc03de22011-12-06 23:28:12262 delegate_->Attach();
[email protected]35869622012-10-26 23:23:55263 Init(true /* actively downloading */, SRC_SAVE_PAGE_AS);
[email protected]c09a8fd2011-11-21 19:54:50264}
265
266DownloadItemImpl::~DownloadItemImpl() {
[email protected]0634626a2012-05-03 19:04:26267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]53ac00e82012-10-18 20:59:20268
269 // Should always have been nuked before now, at worst in
270 // DownloadManager shutdown.
271 DCHECK(!download_file_.get());
272
[email protected]7e834f02012-08-09 20:38:56273 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
[email protected]fc03de22011-12-06 23:28:12274 delegate_->AssertStateConsistent(this);
275 delegate_->Detach();
[email protected]c09a8fd2011-11-21 19:54:50276}
277
278void DownloadItemImpl::AddObserver(Observer* observer) {
[email protected]0634626a2012-05-03 19:04:26279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50280
281 observers_.AddObserver(observer);
282}
283
284void DownloadItemImpl::RemoveObserver(Observer* observer) {
[email protected]0634626a2012-05-03 19:04:26285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50286
287 observers_.RemoveObserver(observer);
288}
289
290void DownloadItemImpl::UpdateObservers() {
[email protected]0634626a2012-05-03 19:04:26291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50292
293 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
294}
295
[email protected]4d4c5222012-09-06 19:29:22296void DownloadItemImpl::DangerousDownloadValidated() {
297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]db6234e2012-09-25 17:23:01298 DCHECK_EQ(IN_PROGRESS, GetState());
[email protected]4d4c5222012-09-06 19:29:22299 DCHECK_EQ(DANGEROUS, GetSafetyState());
300
[email protected]3d95e542012-11-20 00:52:08301 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
302
[email protected]db6234e2012-09-25 17:23:01303 if (GetState() != IN_PROGRESS)
304 return;
305
[email protected]4d4c5222012-09-06 19:29:22306 UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated",
307 GetDangerType(),
[email protected]35869622012-10-26 23:23:55308 DOWNLOAD_DANGER_TYPE_MAX);
[email protected]4d4c5222012-09-06 19:29:22309
310 safety_state_ = DANGEROUS_BUT_VALIDATED;
311
312 bound_net_log_.AddEvent(
313 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
[email protected]35869622012-10-26 23:23:55314 base::Bind(&ItemCheckedNetLogCallback,
[email protected]4d4c5222012-09-06 19:29:22315 GetDangerType(), GetSafetyState()));
316
317 UpdateObservers();
318
[email protected]18710a42a2012-10-17 19:50:43319 MaybeCompleteDownload();
[email protected]c09a8fd2011-11-21 19:54:50320}
321
[email protected]4d4c5222012-09-06 19:29:22322void DownloadItemImpl::TogglePause() {
323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d0d368252012-09-24 17:13:42324 DCHECK(state_ == IN_PROGRESS_INTERNAL || state_ == COMPLETING_INTERNAL);
[email protected]3d95e542012-11-20 00:52:08325 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]53ac00e82012-10-18 20:59:20326
327 // Ignore pauses when we've passed the commit point.
328 if (state_ == COMPLETING_INTERNAL)
329 return;
330
[email protected]4d4c5222012-09-06 19:29:22331 if (is_paused_)
332 request_handle_->ResumeRequest();
333 else
334 request_handle_->PauseRequest();
335 is_paused_ = !is_paused_;
336 UpdateObservers();
[email protected]c09a8fd2011-11-21 19:54:50337}
338
[email protected]4d4c5222012-09-06 19:29:22339void DownloadItemImpl::Cancel(bool user_cancel) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341
342 last_reason_ = user_cancel ?
[email protected]35869622012-10-26 23:23:55343 DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
344 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
[email protected]4d4c5222012-09-06 19:29:22345
346 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
[email protected]d0d368252012-09-24 17:13:42347 if (state_ != IN_PROGRESS_INTERNAL) {
[email protected]4d4c5222012-09-06 19:29:22348 // Small downloads might be complete before this method has
349 // a chance to run.
350 return;
351 }
352
[email protected]35869622012-10-26 23:23:55353 RecordDownloadCount(CANCELLED_COUNT);
[email protected]4d4c5222012-09-06 19:29:22354
[email protected]d0d368252012-09-24 17:13:42355 TransitionTo(CANCELLED_INTERNAL);
[email protected]53ac00e82012-10-18 20:59:20356
357 CancelDownloadFile();
358
359 // Cancel the originating URL request.
360 request_handle_->CancelRequest();
[email protected]4d4c5222012-09-06 19:29:22361}
362
363void DownloadItemImpl::Delete(DeleteReason reason) {
364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
365
366 switch (reason) {
367 case DELETE_DUE_TO_USER_DISCARD:
368 UMA_HISTOGRAM_ENUMERATION(
369 "Download.UserDiscard", GetDangerType(),
[email protected]35869622012-10-26 23:23:55370 DOWNLOAD_DANGER_TYPE_MAX);
[email protected]4d4c5222012-09-06 19:29:22371 break;
372 case DELETE_DUE_TO_BROWSER_SHUTDOWN:
373 UMA_HISTOGRAM_ENUMERATION(
374 "Download.Discard", GetDangerType(),
[email protected]35869622012-10-26 23:23:55375 DOWNLOAD_DANGER_TYPE_MAX);
[email protected]4d4c5222012-09-06 19:29:22376 break;
377 default:
378 NOTREACHED();
379 }
380
[email protected]53ac00e82012-10-18 20:59:20381 // Delete the file if it exists and is not owned by a DownloadFile object.
382 // (In the latter case the DownloadFile object will delete it on cancel.)
383 if (!current_path_.empty() && download_file_.get() == NULL) {
[email protected]4d4c5222012-09-06 19:29:22384 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
385 base::Bind(&DeleteDownloadedFile, current_path_));
[email protected]53ac00e82012-10-18 20:59:20386 }
[email protected]4d4c5222012-09-06 19:29:22387 Remove();
388 // We have now been deleted.
389}
390
391void DownloadItemImpl::Remove() {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393
394 delegate_->AssertStateConsistent(this);
395 Cancel(true);
396 delegate_->AssertStateConsistent(this);
397
398 NotifyRemoved();
399 delegate_->DownloadRemoved(this);
400 // We have now been deleted.
[email protected]c09a8fd2011-11-21 19:54:50401}
402
403void DownloadItemImpl::OpenDownload() {
[email protected]0634626a2012-05-03 19:04:26404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50405
[email protected]d0d368252012-09-24 17:13:42406 if (state_ == IN_PROGRESS_INTERNAL) {
[email protected]71f55842012-03-24 04:09:02407 // We don't honor the open_when_complete_ flag for temporary
408 // downloads. Don't set it because it shows up in the UI.
409 if (!IsTemporary())
410 open_when_complete_ = !open_when_complete_;
[email protected]c09a8fd2011-11-21 19:54:50411 return;
412 }
413
[email protected]d0d368252012-09-24 17:13:42414 if (state_ != COMPLETE_INTERNAL || file_externally_removed_)
[email protected]c09a8fd2011-11-21 19:54:50415 return;
416
417 // Ideally, we want to detect errors in opening and report them, but we
418 // don't generally have the proper interface for that to the external
419 // program that opens the file. So instead we spawn a check to update
420 // the UI if the file has been deleted in parallel with the open.
[email protected]fc03de22011-12-06 23:28:12421 delegate_->CheckForFileRemoval(this);
[email protected]35869622012-10-26 23:23:55422 RecordOpen(GetEndTime(), !GetOpened());
[email protected]c09a8fd2011-11-21 19:54:50423 opened_ = true;
424 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
[email protected]fc03de22011-12-06 23:28:12425 delegate_->DownloadOpened(this);
[email protected]c09a8fd2011-11-21 19:54:50426
427 // For testing: If download opening is disabled on this item,
428 // make the rest of the routine a no-op.
429 if (!open_enabled_)
430 return;
431
[email protected]35869622012-10-26 23:23:55432 GetContentClient()->browser()->OpenItem(GetFullPath());
[email protected]c09a8fd2011-11-21 19:54:50433}
434
435void DownloadItemImpl::ShowDownloadInShell() {
[email protected]0634626a2012-05-03 19:04:26436 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50437
[email protected]35869622012-10-26 23:23:55438 GetContentClient()->browser()->ShowItemInFolder(GetFullPath());
[email protected]c09a8fd2011-11-21 19:54:50439}
440
[email protected]4d4c5222012-09-06 19:29:22441int32 DownloadItemImpl::GetId() const {
442 return download_id_.local();
[email protected]c09a8fd2011-11-21 19:54:50443}
444
[email protected]4d4c5222012-09-06 19:29:22445DownloadId DownloadItemImpl::GetGlobalId() const {
446 return download_id_;
447}
448
[email protected]4d4c5222012-09-06 19:29:22449DownloadItem::DownloadState DownloadItemImpl::GetState() const {
[email protected]d0d368252012-09-24 17:13:42450 return InternalToExternalState(state_);
[email protected]4d4c5222012-09-06 19:29:22451}
452
[email protected]35869622012-10-26 23:23:55453DownloadInterruptReason DownloadItemImpl::GetLastReason() const {
[email protected]4d4c5222012-09-06 19:29:22454 return last_reason_;
455}
456
457bool DownloadItemImpl::IsPaused() const {
458 return is_paused_;
459}
460
461bool DownloadItemImpl::IsTemporary() const {
462 return is_temporary_;
463}
464
[email protected]4d4c5222012-09-06 19:29:22465// TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to
466// |IsPartialDownload()|, when resuming interrupted downloads is implemented.
467bool DownloadItemImpl::IsPartialDownload() const {
[email protected]d0d368252012-09-24 17:13:42468 return InternalToExternalState(state_) == IN_PROGRESS;
[email protected]4d4c5222012-09-06 19:29:22469}
470
471bool DownloadItemImpl::IsInProgress() const {
[email protected]d0d368252012-09-24 17:13:42472 return InternalToExternalState(state_) == IN_PROGRESS;
[email protected]4d4c5222012-09-06 19:29:22473}
474
475bool DownloadItemImpl::IsCancelled() const {
[email protected]d0d368252012-09-24 17:13:42476 DownloadState external_state = InternalToExternalState(state_);
477 return external_state == CANCELLED || external_state == INTERRUPTED;
[email protected]4d4c5222012-09-06 19:29:22478}
479
480bool DownloadItemImpl::IsInterrupted() const {
[email protected]d0d368252012-09-24 17:13:42481 return InternalToExternalState(state_) == INTERRUPTED;
[email protected]4d4c5222012-09-06 19:29:22482}
483
484bool DownloadItemImpl::IsComplete() const {
[email protected]d0d368252012-09-24 17:13:42485 return InternalToExternalState(state_) == COMPLETE;
[email protected]4d4c5222012-09-06 19:29:22486}
487
488const GURL& DownloadItemImpl::GetURL() const {
489 return url_chain_.empty() ?
490 GURL::EmptyGURL() : url_chain_.back();
491}
492
493const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const {
494 return url_chain_;
495}
496
497const GURL& DownloadItemImpl::GetOriginalUrl() const {
498 return url_chain_.front();
499}
500
501const GURL& DownloadItemImpl::GetReferrerUrl() const {
502 return referrer_url_;
503}
504
505std::string DownloadItemImpl::GetSuggestedFilename() const {
506 return suggested_filename_;
507}
508
509std::string DownloadItemImpl::GetContentDisposition() const {
510 return content_disposition_;
511}
512
513std::string DownloadItemImpl::GetMimeType() const {
514 return mime_type_;
515}
516
517std::string DownloadItemImpl::GetOriginalMimeType() const {
518 return original_mime_type_;
519}
520
[email protected]4d4c5222012-09-06 19:29:22521std::string DownloadItemImpl::GetRemoteAddress() const {
522 return remote_address_;
523}
524
525bool DownloadItemImpl::HasUserGesture() const {
526 return has_user_gesture_;
527};
528
[email protected]35869622012-10-26 23:23:55529PageTransition DownloadItemImpl::GetTransitionType() const {
[email protected]4d4c5222012-09-06 19:29:22530 return transition_type_;
531};
532
533const std::string& DownloadItemImpl::GetLastModifiedTime() const {
534 return last_modified_time_;
535}
536
537const std::string& DownloadItemImpl::GetETag() const {
538 return etag_;
539}
540
[email protected]fb904eb52012-11-05 18:54:55541bool DownloadItemImpl::IsSavePackageDownload() const {
542 return is_save_package_download_;
543}
544
[email protected]4d4c5222012-09-06 19:29:22545const FilePath& DownloadItemImpl::GetFullPath() const {
546 return current_path_;
547}
548
549const FilePath& DownloadItemImpl::GetTargetFilePath() const {
550 return target_path_;
551}
552
[email protected]4d4c5222012-09-06 19:29:22553const FilePath& DownloadItemImpl::GetForcedFilePath() const {
554 // TODO(asanka): Get rid of GetForcedFilePath(). We should instead just
555 // require that clients respect GetTargetFilePath() if it is already set.
556 return forced_file_path_;
557}
558
559FilePath DownloadItemImpl::GetUserVerifiedFilePath() const {
560 return (safety_state_ == DownloadItem::SAFE) ?
561 GetTargetFilePath() : GetFullPath();
562}
563
564FilePath DownloadItemImpl::GetFileNameToReportUser() const {
565 if (!display_name_.empty())
566 return display_name_;
567 return target_path_.BaseName();
568}
569
570DownloadItem::TargetDisposition DownloadItemImpl::GetTargetDisposition() const {
571 return target_disposition_;
572}
573
574const std::string& DownloadItemImpl::GetHash() const {
575 return hash_;
576}
577
578const std::string& DownloadItemImpl::GetHashState() const {
579 return hash_state_;
580}
581
582bool DownloadItemImpl::GetFileExternallyRemoved() const {
583 return file_externally_removed_;
584}
585
586// TODO(asanka): Unify GetSafetyState() and IsDangerous().
587DownloadItem::SafetyState DownloadItemImpl::GetSafetyState() const {
588 return safety_state_;
589}
590
591bool DownloadItemImpl::IsDangerous() const {
592 // TODO(noelutz): At this point only the windows views UI supports
593 // warnings based on dangerous content.
594#ifdef OS_WIN
[email protected]35869622012-10-26 23:23:55595 return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
596 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
597 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
598 danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT);
[email protected]4d4c5222012-09-06 19:29:22599#else
[email protected]35869622012-10-26 23:23:55600 return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
601 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
[email protected]4d4c5222012-09-06 19:29:22602#endif
603}
604
[email protected]35869622012-10-26 23:23:55605DownloadDangerType DownloadItemImpl::GetDangerType() const {
[email protected]4d4c5222012-09-06 19:29:22606 return danger_type_;
607}
608
609bool DownloadItemImpl::TimeRemaining(base::TimeDelta* remaining) const {
610 if (total_bytes_ <= 0)
611 return false; // We never received the content_length for this download.
612
613 int64 speed = CurrentSpeed();
614 if (speed == 0)
615 return false;
616
617 *remaining = base::TimeDelta::FromSeconds(
618 (total_bytes_ - received_bytes_) / speed);
619 return true;
620}
621
622int64 DownloadItemImpl::CurrentSpeed() const {
623 if (is_paused_)
624 return 0;
625 return bytes_per_sec_;
626}
627
628int DownloadItemImpl::PercentComplete() const {
629 // If the delegate is delaying completion of the download, then we have no
630 // idea how long it will take.
631 if (delegate_delayed_complete_ || total_bytes_ <= 0)
632 return -1;
633
634 return static_cast<int>(received_bytes_ * 100.0 / total_bytes_);
635}
636
637bool DownloadItemImpl::AllDataSaved() const {
638 return all_data_saved_;
639}
640
641int64 DownloadItemImpl::GetTotalBytes() const {
642 return total_bytes_;
643}
644
645int64 DownloadItemImpl::GetReceivedBytes() const {
646 return received_bytes_;
647}
648
649base::Time DownloadItemImpl::GetStartTime() const {
650 return start_time_;
651}
652
653base::Time DownloadItemImpl::GetEndTime() const {
654 return end_time_;
655}
656
657bool DownloadItemImpl::CanShowInFolder() {
[email protected]35b176f2012-12-27 01:38:03658 // A download can be shown in the folder if the downloaded file is in a known
659 // location.
660 return CanOpenDownload() && !GetFullPath().empty();
[email protected]4d4c5222012-09-06 19:29:22661}
662
663bool DownloadItemImpl::CanOpenDownload() {
[email protected]35b176f2012-12-27 01:38:03664 // We can open the file or mark it for opening on completion if the download
665 // is expected to complete successfully. Exclude temporary downloads, since
666 // they aren't owned by the download system.
667 return (IsInProgress() || IsComplete()) && !IsTemporary() &&
668 !file_externally_removed_;
[email protected]4d4c5222012-09-06 19:29:22669}
670
671bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
672 return delegate_->ShouldOpenFileBasedOnExtension(GetUserVerifiedFilePath());
673}
674
675bool DownloadItemImpl::GetOpenWhenComplete() const {
676 return open_when_complete_;
677}
678
679bool DownloadItemImpl::GetAutoOpened() {
680 return auto_opened_;
681}
682
683bool DownloadItemImpl::GetOpened() const {
684 return opened_;
685}
686
[email protected]35869622012-10-26 23:23:55687BrowserContext* DownloadItemImpl::GetBrowserContext() const {
[email protected]4d4c5222012-09-06 19:29:22688 return delegate_->GetBrowserContext();
689}
690
691WebContents* DownloadItemImpl::GetWebContents() const {
692 // TODO(rdsmith): Remove null check after removing GetWebContents() from
693 // paths that might be used by DownloadItems created from history import.
694 // Currently such items have null request_handle_s, where other items
695 // (regular and SavePackage downloads) have actual objects off the pointer.
696 if (request_handle_.get())
697 return request_handle_->GetWebContents();
698 return NULL;
699}
700
[email protected]35869622012-10-26 23:23:55701void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) {
[email protected]96c3bdbaa2012-08-31 16:39:54702 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]4d4c5222012-09-06 19:29:22703 DCHECK(AllDataSaved());
[email protected]3d95e542012-11-20 00:52:08704 VLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
705 << " download=" << DebugString(true);
[email protected]4d4c5222012-09-06 19:29:22706 SetDangerType(danger_type);
707 UpdateObservers();
708}
[email protected]96c3bdbaa2012-08-31 16:39:54709
[email protected]4d4c5222012-09-06 19:29:22710void DownloadItemImpl::SetOpenWhenComplete(bool open) {
711 open_when_complete_ = open;
712}
[email protected]96c3bdbaa2012-08-31 16:39:54713
[email protected]4d4c5222012-09-06 19:29:22714void DownloadItemImpl::SetIsTemporary(bool temporary) {
715 is_temporary_ = temporary;
716}
[email protected]96c3bdbaa2012-08-31 16:39:54717
[email protected]4d4c5222012-09-06 19:29:22718void DownloadItemImpl::SetOpened(bool opened) {
719 opened_ = opened;
720}
721
722void DownloadItemImpl::SetDisplayName(const FilePath& name) {
723 display_name_ = name;
724}
725
726std::string DownloadItemImpl::DebugString(bool verbose) const {
727 std::string description =
728 base::StringPrintf("{ id = %d"
729 " state = %s",
730 download_id_.local(),
[email protected]d0d368252012-09-24 17:13:42731 DebugDownloadStateString(state_));
[email protected]4d4c5222012-09-06 19:29:22732
733 // Construct a string of the URL chain.
734 std::string url_list("<none>");
735 if (!url_chain_.empty()) {
736 std::vector<GURL>::const_iterator iter = url_chain_.begin();
737 std::vector<GURL>::const_iterator last = url_chain_.end();
738 url_list = (*iter).spec();
739 ++iter;
740 for ( ; verbose && (iter != last); ++iter) {
741 url_list += " ->\n\t";
742 const GURL& next_url = *iter;
743 url_list += next_url.spec();
744 }
745 }
746
747 if (verbose) {
748 description += base::StringPrintf(
[email protected]4d4c5222012-09-06 19:29:22749 " total = %" PRId64
750 " received = %" PRId64
751 " reason = %s"
752 " paused = %c"
753 " safety = %s"
754 " last_modified = '%s'"
755 " etag = '%s'"
756 " url_chain = \n\t\"%s\"\n\t"
757 " full_path = \"%" PRFilePath "\""
[email protected]53ac00e82012-10-18 20:59:20758 " target_path = \"%" PRFilePath "\""
759 " has download file = %s",
[email protected]4d4c5222012-09-06 19:29:22760 GetTotalBytes(),
761 GetReceivedBytes(),
762 InterruptReasonDebugString(last_reason_).c_str(),
763 IsPaused() ? 'T' : 'F',
764 DebugSafetyStateString(GetSafetyState()),
765 GetLastModifiedTime().c_str(),
766 GetETag().c_str(),
767 url_list.c_str(),
768 GetFullPath().value().c_str(),
[email protected]53ac00e82012-10-18 20:59:20769 GetTargetFilePath().value().c_str(),
770 download_file_.get() ? "true" : "false");
[email protected]4d4c5222012-09-06 19:29:22771 } else {
772 description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
773 }
774
775 description += " }";
776
777 return description;
778}
779
780void DownloadItemImpl::MockDownloadOpenForTesting() {
781 open_enabled_ = false;
782}
783
784void DownloadItemImpl::NotifyRemoved() {
785 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
786}
787
788void DownloadItemImpl::OnDownloadedFileRemoved() {
789 file_externally_removed_ = true;
[email protected]3d95e542012-11-20 00:52:08790 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]4d4c5222012-09-06 19:29:22791 UpdateObservers();
792}
793
[email protected]35869622012-10-26 23:23:55794base::WeakPtr<DownloadDestinationObserver>
[email protected]53ac00e82012-10-18 20:59:20795DownloadItemImpl::DestinationObserverAsWeakPtr() {
796 return weak_ptr_factory_.GetWeakPtr();
797}
798
[email protected]4d4c5222012-09-06 19:29:22799void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
800 total_bytes_ = total_bytes;
[email protected]96c3bdbaa2012-08-31 16:39:54801}
802
[email protected]16dcd302012-07-02 17:16:51803// Updates from the download thread may have been posted while this download
804// was being cancelled in the UI thread, so we'll accept them unless we're
805// complete.
[email protected]443853c62011-12-22 19:22:41806void DownloadItemImpl::UpdateProgress(int64 bytes_so_far,
[email protected]16dcd302012-07-02 17:16:51807 int64 bytes_per_sec,
[email protected]443853c62011-12-22 19:22:41808 const std::string& hash_state) {
[email protected]16dcd302012-07-02 17:16:51809 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d95e542012-11-20 00:52:08810 VLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
811 << " per_sec=" << bytes_per_sec << " download=" << DebugString(true);
[email protected]336721e2012-06-29 08:09:38812
[email protected]d0d368252012-09-24 17:13:42813 if (state_ != IN_PROGRESS_INTERNAL) {
[email protected]16dcd302012-07-02 17:16:51814 // Ignore if we're no longer in-progress. This can happen if we race a
815 // Cancel on the UI thread with an update on the FILE thread.
816 //
817 // TODO(rdsmith): Arguably we should let this go through, as this means
818 // the download really did get further than we know before it was
819 // cancelled. But the gain isn't very large, and the code is more
820 // fragile if it has to support in progress updates in a non-in-progress
821 // state. This issue should be readdressed when we revamp performance
822 // reporting.
823 return;
824 }
825 bytes_per_sec_ = bytes_per_sec;
826 hash_state_ = hash_state;
[email protected]c09a8fd2011-11-21 19:54:50827 received_bytes_ = bytes_so_far;
828
829 // If we've received more data than we were expecting (bad server info?),
830 // revert to 'unknown size mode'.
831 if (received_bytes_ > total_bytes_)
832 total_bytes_ = 0;
[email protected]a6e12012012-02-08 02:24:08833
834 if (bound_net_log_.IsLoggingAllEvents()) {
835 bound_net_log_.AddEvent(
836 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
[email protected]2fa08912012-06-14 20:56:26837 net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
[email protected]a6e12012012-02-08 02:24:08838 }
[email protected]c09a8fd2011-11-21 19:54:50839
[email protected]c09a8fd2011-11-21 19:54:50840 UpdateObservers();
841}
842
[email protected]53ac00e82012-10-18 20:59:20843void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
[email protected]0634626a2012-05-03 19:04:26844 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:50845
[email protected]53ac00e82012-10-18 20:59:20846 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
[email protected]c09a8fd2011-11-21 19:54:50847 DCHECK(!all_data_saved_);
848 all_data_saved_ = true;
[email protected]3d95e542012-11-20 00:52:08849 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]53ac00e82012-10-18 20:59:20850
851 // Store final hash and null out intermediate serialized hash state.
852 hash_ = final_hash;
853 hash_state_ = "";
854
[email protected]196e9722012-03-28 05:14:04855 UpdateObservers();
[email protected]c09a8fd2011-11-21 19:54:50856}
857
[email protected]4d4c5222012-09-06 19:29:22858void DownloadItemImpl::MarkAsComplete() {
859 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
860
861 DCHECK(all_data_saved_);
862 end_time_ = base::Time::Now();
[email protected]d0d368252012-09-24 17:13:42863 TransitionTo(COMPLETE_INTERNAL);
[email protected]4d4c5222012-09-06 19:29:22864}
[email protected]53ac00e82012-10-18 20:59:20865void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far,
866 int64 bytes_per_sec,
867 const std::string& hash_state) {
868 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d95e542012-11-20 00:52:08869 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]53ac00e82012-10-18 20:59:20870
871 if (!IsInProgress()) {
872 // Ignore if we're no longer in-progress. This can happen if we race a
873 // Cancel on the UI thread with an update on the FILE thread.
874 //
875 // TODO(rdsmith): Arguably we should let this go through, as this means
876 // the download really did get further than we know before it was
877 // cancelled. But the gain isn't very large, and the code is more
878 // fragile if it has to support in progress updates in a non-in-progress
879 // state. This issue should be readdressed when we revamp performance
880 // reporting.
881 return;
882 }
883 bytes_per_sec_ = bytes_per_sec;
884 hash_state_ = hash_state;
885 received_bytes_ = bytes_so_far;
886
887 // If we've received more data than we were expecting (bad server info?),
888 // revert to 'unknown size mode'.
889 if (received_bytes_ > total_bytes_)
890 total_bytes_ = 0;
891
892 if (bound_net_log_.IsLoggingAllEvents()) {
893 bound_net_log_.AddEvent(
894 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
895 net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
896 }
897
898 UpdateObservers();
899}
900
[email protected]35869622012-10-26 23:23:55901void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
[email protected]53ac00e82012-10-18 20:59:20902 // The DestinationError and Interrupt routines are being kept separate
[email protected]3d95e542012-11-20 00:52:08903 // to allow for a future merging of the Cancel and Interrupt routines.
[email protected]53ac00e82012-10-18 20:59:20904 Interrupt(reason);
905}
906
907void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
[email protected]3d95e542012-11-20 00:52:08908 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]53ac00e82012-10-18 20:59:20909 if (!IsInProgress())
910 return;
911 OnAllDataSaved(final_hash);
912 MaybeCompleteDownload();
913}
914
[email protected]4d4c5222012-09-06 19:29:22915// **** Download progression cascade
916
917void DownloadItemImpl::Init(bool active,
[email protected]35869622012-10-26 23:23:55918 DownloadType download_type) {
[email protected]4d4c5222012-09-06 19:29:22919 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
920
921 if (active)
[email protected]35869622012-10-26 23:23:55922 RecordDownloadCount(START_COUNT);
[email protected]4d4c5222012-09-06 19:29:22923
924 if (target_path_.empty())
925 target_path_ = current_path_;
926 std::string file_name;
[email protected]35869622012-10-26 23:23:55927 if (download_type == SRC_HISTORY_IMPORT) {
[email protected]4d4c5222012-09-06 19:29:22928 // target_path_ works for History and Save As versions.
929 file_name = target_path_.AsUTF8Unsafe();
930 } else {
931 // See if it's set programmatically.
932 file_name = forced_file_path_.AsUTF8Unsafe();
933 // Possibly has a 'download' attribute for the anchor.
934 if (file_name.empty())
935 file_name = suggested_filename_;
936 // From the URL file name.
937 if (file_name.empty())
938 file_name = GetURL().ExtractFileName();
939 }
940
[email protected]3d95e542012-11-20 00:52:08941 base::Callback<base::Value*(net::NetLog::LogLevel)> active_data = base::Bind(
942 &ItemActivatedNetLogCallback, this, download_type, &file_name);
943 if (active) {
944 bound_net_log_.BeginEvent(
945 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
946 } else {
[email protected]4d4c5222012-09-06 19:29:22947 bound_net_log_.AddEvent(
[email protected]3d95e542012-11-20 00:52:08948 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
[email protected]4d4c5222012-09-06 19:29:22949 }
950
951 VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
952}
953
[email protected]53ac00e82012-10-18 20:59:20954// We're starting the download.
[email protected]35869622012-10-26 23:23:55955void DownloadItemImpl::Start(scoped_ptr<DownloadFile> file) {
[email protected]53ac00e82012-10-18 20:59:20956 DCHECK(!download_file_.get());
957 DCHECK(file.get());
958 download_file_ = file.Pass();
959
960 BrowserThread::PostTask(
961 BrowserThread::FILE, FROM_HERE,
962 base::Bind(&DownloadFile::Initialize,
963 // Safe because we control download file lifetime.
964 base::Unretained(download_file_.get()),
965 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
966 weak_ptr_factory_.GetWeakPtr())));
967}
968
969void DownloadItemImpl::OnDownloadFileInitialized(
[email protected]35869622012-10-26 23:23:55970 DownloadInterruptReason result) {
971 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
[email protected]53ac00e82012-10-18 20:59:20972 Interrupt(result);
973 // TODO(rdsmith): It makes no sense to continue along the
974 // regular download path after we've gotten an error. But it's
975 // the way the code has historically worked, and this allows us
976 // to get the download persisted and observers of the download manager
977 // notified, so tests work. When we execute all side effects of cancel
978 // (including queue removal) immedately rather than waiting for
979 // persistence we should replace this comment with a "return;".
980 }
981
982 delegate_->DetermineDownloadTarget(
983 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
984 weak_ptr_factory_.GetWeakPtr()));
985}
986
987// Called by delegate_ when the download target path has been
[email protected]4d4c5222012-09-06 19:29:22988// determined.
989void DownloadItemImpl::OnDownloadTargetDetermined(
990 const FilePath& target_path,
991 TargetDisposition disposition,
[email protected]35869622012-10-26 23:23:55992 DownloadDangerType danger_type,
[email protected]4d4c5222012-09-06 19:29:22993 const FilePath& intermediate_path) {
994 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
995
996 // If the |target_path| is empty, then we consider this download to be
997 // canceled.
998 if (target_path.empty()) {
999 Cancel(true);
1000 return;
1001 }
1002
[email protected]3d95e542012-11-20 00:52:081003 VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
1004 << " " << danger_type << " " << DebugString(true);
1005
[email protected]4d4c5222012-09-06 19:29:221006 target_path_ = target_path;
1007 target_disposition_ = disposition;
1008 SetDangerType(danger_type);
1009 // TODO(asanka): SetDangerType() doesn't need to send a notification here.
1010
1011 // We want the intermediate and target paths to refer to the same directory so
1012 // that they are both on the same device and subject to same
1013 // space/permission/availability constraints.
1014 DCHECK(intermediate_path.DirName() == target_path.DirName());
1015
[email protected]d0d368252012-09-24 17:13:421016 if (state_ != IN_PROGRESS_INTERNAL) {
1017 // If we've been cancelled or interrupted while the target was being
1018 // determined, continue the cascade with a null name.
1019 // The error doesn't matter as the cause of download stoppage
1020 // will already have been recorded and will be retained, but we use
1021 // whatever was recorded for consistency.
1022 OnDownloadRenamedToIntermediateName(last_reason_, FilePath());
1023 return;
1024 }
1025
[email protected]4d4c5222012-09-06 19:29:221026 // Rename to intermediate name.
1027 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
1028 // spurious rename when we can just rename to the final
1029 // filename. Unnecessary renames may cause bugs like
1030 // http://crbug.com/74187.
[email protected]53ac00e82012-10-18 20:59:201031 DCHECK(!is_save_package_download_);
[email protected]dd7ef802012-10-25 20:59:241032 DCHECK(download_file_.get());
[email protected]53ac00e82012-10-18 20:59:201033 DownloadFile::RenameCompletionCallback callback =
[email protected]4d4c5222012-09-06 19:29:221034 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
1035 weak_ptr_factory_.GetWeakPtr());
1036 BrowserThread::PostTask(
1037 BrowserThread::FILE, FROM_HERE,
[email protected]d6825972012-11-10 01:22:521038 base::Bind(&DownloadFile::RenameAndUniquify,
[email protected]53ac00e82012-10-18 20:59:201039 // Safe because we control download file lifetime.
1040 base::Unretained(download_file_.get()),
[email protected]d6825972012-11-10 01:22:521041 intermediate_path, callback));
[email protected]4d4c5222012-09-06 19:29:221042}
1043
1044void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
[email protected]35869622012-10-26 23:23:551045 DownloadInterruptReason reason,
[email protected]4d4c5222012-09-06 19:29:221046 const FilePath& full_path) {
1047 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d95e542012-11-20 00:52:081048 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
[email protected]5fb71452012-12-11 21:37:221049 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason)
[email protected]4d4c5222012-09-06 19:29:221050 Interrupt(reason);
[email protected]5fb71452012-12-11 21:37:221051 else
[email protected]4d4c5222012-09-06 19:29:221052 SetFullPath(full_path);
[email protected]5fb71452012-12-11 21:37:221053 delegate_->ShowDownloadInBrowser(this);
[email protected]4d4c5222012-09-06 19:29:221054
[email protected]3d95e542012-11-20 00:52:081055 MaybeCompleteDownload();
[email protected]c09a8fd2011-11-21 19:54:501056}
1057
[email protected]18710a42a2012-10-17 19:50:431058// When SavePackage downloads MHTML to GData (see
1059// SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
1060// does for non-SavePackage downloads, but SavePackage downloads never satisfy
1061// IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
1062// DownloadItem::UpdateObservers() when the upload completes so that SavePackage
1063// notices that the upload has completed and runs its normal Finish() pathway.
1064// MaybeCompleteDownload() is never the mechanism by which SavePackage completes
1065// downloads. SavePackage always uses its own Finish() to mark downloads
1066// complete.
[email protected]fc03de22011-12-06 23:28:121067void DownloadItemImpl::MaybeCompleteDownload() {
[email protected]18710a42a2012-10-17 19:50:431068 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d6825972012-11-10 01:22:521069 DCHECK(!is_save_package_download_);
[email protected]18710a42a2012-10-17 19:50:431070
1071 if (!IsDownloadReadyForCompletion())
1072 return;
1073
1074 // TODO(rdsmith): DCHECK that we only pass through this point
1075 // once per download. The natural way to do this is by a state
1076 // transition on the DownloadItem.
1077
1078 // Confirm we're in the proper set of states to be here;
1079 // have all data, have a history handle, (validated or safe).
1080 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
1081 DCHECK_NE(DownloadItem::DANGEROUS, GetSafetyState());
1082 DCHECK(all_data_saved_);
[email protected]18710a42a2012-10-17 19:50:431083
1084 OnDownloadCompleting();
[email protected]fc03de22011-12-06 23:28:121085}
1086
[email protected]18710a42a2012-10-17 19:50:431087// Called by MaybeCompleteDownload() when it has determined that the download
1088// is ready for completion.
[email protected]4d4c5222012-09-06 19:29:221089void DownloadItemImpl::OnDownloadCompleting() {
1090 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1091
[email protected]d0d368252012-09-24 17:13:421092 if (state_ != IN_PROGRESS_INTERNAL)
1093 return;
1094
[email protected]18710a42a2012-10-17 19:50:431095 // Give the delegate a chance to override.
1096 delegate_->ReadyForDownloadCompletion(
1097 this, base::Bind(&DownloadItemImpl::ReadyForDownloadCompletionDone,
1098 weak_ptr_factory_.GetWeakPtr()));
1099}
1100
1101void DownloadItemImpl::ReadyForDownloadCompletionDone() {
1102 if (state_ != IN_PROGRESS_INTERNAL)
1103 return;
1104
[email protected]4d4c5222012-09-06 19:29:221105 VLOG(20) << __FUNCTION__ << "()"
[email protected]4d4c5222012-09-06 19:29:221106 << " " << DebugString(true);
[email protected]e9e6b122012-09-12 19:21:451107 DCHECK(!GetTargetFilePath().empty());
[email protected]4d4c5222012-09-06 19:29:221108 DCHECK_NE(DANGEROUS, GetSafetyState());
1109
[email protected]53ac00e82012-10-18 20:59:201110 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
1111 if (is_save_package_download_) {
1112 // Avoid doing anything on the file thread; there's nothing we control
1113 // there.
[email protected]d6825972012-11-10 01:22:521114 // Strictly speaking, this skips giving the embedder a chance to open
1115 // the download. But on a save package download, there's no real
1116 // concept of opening.
1117 Completed();
[email protected]53ac00e82012-10-18 20:59:201118 return;
1119 }
1120
[email protected]dd7ef802012-10-25 20:59:241121 DCHECK(download_file_.get());
[email protected]d6825972012-11-10 01:22:521122 // Unilaterally rename; even if it already has the right name,
1123 // we need theannotation.
1124 DownloadFile::RenameCompletionCallback callback =
1125 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName,
1126 weak_ptr_factory_.GetWeakPtr());
1127 BrowserThread::PostTask(
1128 BrowserThread::FILE, FROM_HERE,
1129 base::Bind(&DownloadFile::RenameAndAnnotate,
1130 base::Unretained(download_file_.get()),
1131 GetTargetFilePath(), callback));
[email protected]4d4c5222012-09-06 19:29:221132}
1133
1134void DownloadItemImpl::OnDownloadRenamedToFinalName(
[email protected]35869622012-10-26 23:23:551135 DownloadInterruptReason reason,
[email protected]4d4c5222012-09-06 19:29:221136 const FilePath& full_path) {
1137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d6825972012-11-10 01:22:521138 DCHECK(!is_save_package_download_);
[email protected]4d4c5222012-09-06 19:29:221139
[email protected]d0d368252012-09-24 17:13:421140 // If a cancel or interrupt hit, we'll cancel the DownloadFile, which
1141 // will result in deleting the file on the file thread. So we don't
1142 // care about the name having been changed.
1143 if (state_ != IN_PROGRESS_INTERNAL)
1144 return;
1145
[email protected]4d4c5222012-09-06 19:29:221146 VLOG(20) << __FUNCTION__ << "()"
1147 << " full_path = \"" << full_path.value() << "\""
[email protected]4d4c5222012-09-06 19:29:221148 << " " << DebugString(false);
[email protected]4d4c5222012-09-06 19:29:221149
[email protected]35869622012-10-26 23:23:551150 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
[email protected]4d4c5222012-09-06 19:29:221151 Interrupt(reason);
1152 return;
1153 }
1154
[email protected]d6825972012-11-10 01:22:521155 DCHECK(target_path_ == full_path);
[email protected]4d4c5222012-09-06 19:29:221156
[email protected]d6825972012-11-10 01:22:521157 if (full_path != current_path_) {
1158 // full_path is now the current and target file path.
1159 DCHECK(!full_path.empty());
1160 SetFullPath(full_path);
[email protected]d6825972012-11-10 01:22:521161 }
[email protected]53ac00e82012-10-18 20:59:201162
[email protected]4d4c5222012-09-06 19:29:221163 // Complete the download and release the DownloadFile.
[email protected]dd7ef802012-10-25 20:59:241164 DCHECK(download_file_.get());
[email protected]4d4c5222012-09-06 19:29:221165 BrowserThread::PostTask(
1166 BrowserThread::FILE, FROM_HERE,
[email protected]c7e946702012-12-18 11:55:091167 base::Bind(&DownloadFileDetach, base::Passed(&download_file_)));
[email protected]53ac00e82012-10-18 20:59:201168
1169 // We're not completely done with the download item yet, but at this
1170 // point we're committed to complete the download. Cancels (or Interrupts,
1171 // though it's not clear how they could happen) after this point will be
1172 // ignored.
[email protected]d0d368252012-09-24 17:13:421173 TransitionTo(COMPLETING_INTERNAL);
[email protected]4d4c5222012-09-06 19:29:221174
[email protected]bde0e4f2012-11-08 22:49:591175 if (delegate_->ShouldOpenDownload(
1176 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened,
1177 weak_ptr_factory_.GetWeakPtr()))) {
[email protected]4d4c5222012-09-06 19:29:221178 Completed();
[email protected]bde0e4f2012-11-08 22:49:591179 } else {
[email protected]4d4c5222012-09-06 19:29:221180 delegate_delayed_complete_ = true;
[email protected]bde0e4f2012-11-08 22:49:591181 }
[email protected]4d4c5222012-09-06 19:29:221182}
1183
1184void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
1185 auto_opened_ = auto_opened;
1186 Completed();
1187}
1188
[email protected]c09a8fd2011-11-21 19:54:501189void DownloadItemImpl::Completed() {
[email protected]0634626a2012-05-03 19:04:261190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c09a8fd2011-11-21 19:54:501191
1192 VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
1193
[email protected]336721e2012-06-29 08:09:381194 DCHECK(all_data_saved_);
1195 end_time_ = base::Time::Now();
[email protected]d0d368252012-09-24 17:13:421196 TransitionTo(COMPLETE_INTERNAL);
[email protected]35869622012-10-26 23:23:551197 RecordDownloadCompleted(start_tick_, received_bytes_);
[email protected]336721e2012-06-29 08:09:381198
[email protected]c09a8fd2011-11-21 19:54:501199 if (auto_opened_) {
1200 // If it was already handled by the delegate, do nothing.
1201 } else if (GetOpenWhenComplete() ||
1202 ShouldOpenFileBasedOnExtension() ||
1203 IsTemporary()) {
1204 // If the download is temporary, like in drag-and-drop, do not open it but
1205 // we still need to set it auto-opened so that it can be removed from the
1206 // download shelf.
1207 if (!IsTemporary())
1208 OpenDownload();
1209
1210 auto_opened_ = true;
1211 UpdateObservers();
1212 }
1213}
1214
[email protected]4d4c5222012-09-06 19:29:221215// **** End of Download progression cascade
1216
[email protected]bde0e4f2012-11-08 22:49:591217// An error occurred somewhere.
1218void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
1219 // Somewhat counter-intuitively, it is possible for us to receive an
1220 // interrupt after we've already been interrupted. The generation of
1221 // interrupts from the file thread Renames and the generation of
1222 // interrupts from disk writes go through two different mechanisms (driven
1223 // by rename requests from UI thread and by write requests from IO thread,
1224 // respectively), and since we choose not to keep state on the File thread,
1225 // this is the place where the races collide. It's also possible for
1226 // interrupts to race with cancels.
1227
1228 // Whatever happens, the first one to hit the UI thread wins.
[email protected]d6825972012-11-10 01:22:521229 if (state_ != IN_PROGRESS_INTERNAL)
[email protected]bde0e4f2012-11-08 22:49:591230 return;
1231
1232 last_reason_ = reason;
1233 TransitionTo(INTERRUPTED_INTERNAL);
1234
1235 CancelDownloadFile();
1236
1237 // Cancel the originating URL request.
1238 request_handle_->CancelRequest();
1239
1240 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
[email protected]bde0e4f2012-11-08 22:49:591241}
1242
[email protected]53ac00e82012-10-18 20:59:201243void DownloadItemImpl::CancelDownloadFile() {
1244 // TODO(rdsmith/benjhayden): Remove condition as part of
1245 // SavePackage integration.
[email protected]0e13f5c2012-10-29 13:24:061246 // download_file_ can be NULL if Interrupt() is called after the download file
1247 // has been released.
1248 if (!is_save_package_download_ && download_file_.get()) {
[email protected]53ac00e82012-10-18 20:59:201249 BrowserThread::PostTask(
1250 BrowserThread::FILE, FROM_HERE,
1251 // Will be deleted at end of task execution.
[email protected]c7e946702012-12-18 11:55:091252 base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
[email protected]53ac00e82012-10-18 20:59:201253 }
1254}
1255
[email protected]18710a42a2012-10-17 19:50:431256bool DownloadItemImpl::IsDownloadReadyForCompletion() {
[email protected]3d95e542012-11-20 00:52:081257 VLOG(20) << __FUNCTION__ << " " << AllDataSaved()
1258 << " " << (GetSafetyState() != DownloadItem::DANGEROUS)
1259 << " " << (state_ == IN_PROGRESS_INTERNAL)
1260 << " " << !GetTargetFilePath().empty()
1261 << " " << (target_path_.DirName() == current_path_.DirName());
[email protected]18710a42a2012-10-17 19:50:431262 // If we don't have all the data, the download is not ready for
1263 // completion.
1264 if (!AllDataSaved())
1265 return false;
1266
1267 // If the download is dangerous, but not yet validated, it's not ready for
1268 // completion.
1269 if (GetSafetyState() == DownloadItem::DANGEROUS)
1270 return false;
1271
1272 // If the download isn't active (e.g. has been cancelled) it's not
1273 // ready for completion.
1274 if (state_ != IN_PROGRESS_INTERNAL)
1275 return false;
1276
[email protected]3d95e542012-11-20 00:52:081277 // If the target filename hasn't been determined, then it's not ready for
1278 // completion. This is checked in ReadyForDownloadCompletionDone().
1279 if (GetTargetFilePath().empty())
1280 return false;
1281
1282 // This is checked in NeedsRename(). Without this conditional,
1283 // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK.
1284 if (target_path_.DirName() != current_path_.DirName())
[email protected]18710a42a2012-10-17 19:50:431285 return false;
1286
1287 return true;
1288}
1289
[email protected]d0d368252012-09-24 17:13:421290void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
[email protected]c09a8fd2011-11-21 19:54:501291 if (state_ == new_state)
1292 return;
1293
[email protected]d0d368252012-09-24 17:13:421294 DownloadInternalState old_state = state_;
[email protected]c09a8fd2011-11-21 19:54:501295 state_ = new_state;
[email protected]a6e12012012-02-08 02:24:081296
1297 switch (state_) {
[email protected]d0d368252012-09-24 17:13:421298 case COMPLETING_INTERNAL:
1299 bound_net_log_.AddEvent(
1300 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
[email protected]35869622012-10-26 23:23:551301 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
[email protected]d0d368252012-09-24 17:13:421302 break;
1303 case COMPLETE_INTERNAL:
[email protected]a6e12012012-02-08 02:24:081304 bound_net_log_.AddEvent(
1305 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
[email protected]35869622012-10-26 23:23:551306 base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
[email protected]a6e12012012-02-08 02:24:081307 break;
[email protected]d0d368252012-09-24 17:13:421308 case INTERRUPTED_INTERNAL:
[email protected]a6e12012012-02-08 02:24:081309 bound_net_log_.AddEvent(
1310 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
[email protected]35869622012-10-26 23:23:551311 base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
1312 received_bytes_, &hash_state_));
[email protected]a6e12012012-02-08 02:24:081313 break;
[email protected]d0d368252012-09-24 17:13:421314 case CANCELLED_INTERNAL:
[email protected]a6e12012012-02-08 02:24:081315 bound_net_log_.AddEvent(
1316 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
[email protected]35869622012-10-26 23:23:551317 base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
1318 &hash_state_));
[email protected]a6e12012012-02-08 02:24:081319 break;
1320 default:
1321 break;
1322 }
1323
[email protected]3d95e542012-11-20 00:52:081324 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
1325 << " " << InternalToExternalState(old_state)
1326 << " " << InternalToExternalState(state_);
[email protected]1138ff02012-03-14 21:14:281327
[email protected]d0d368252012-09-24 17:13:421328 // Only update observers on user visible state changes.
1329 if (InternalToExternalState(old_state) != InternalToExternalState(state_))
1330 UpdateObservers();
[email protected]a6e12012012-02-08 02:24:081331
[email protected]d0d368252012-09-24 17:13:421332 bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
1333 state_ != COMPLETING_INTERNAL);
1334 bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
1335 old_state != COMPLETING_INTERNAL);
[email protected]a6e12012012-02-08 02:24:081336 if (is_done && !was_done)
[email protected]2fa08912012-06-14 20:56:261337 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
[email protected]c09a8fd2011-11-21 19:54:501338}
1339
[email protected]35869622012-10-26 23:23:551340void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
[email protected]3d833de2012-05-30 23:32:061341 danger_type_ = danger_type;
1342 // Notify observers if the safety state has changed as a result of the new
1343 // danger type.
1344 SafetyState updated_value = IsDangerous() ?
1345 DownloadItem::DANGEROUS : DownloadItem::SAFE;
[email protected]c09a8fd2011-11-21 19:54:501346 if (updated_value != safety_state_) {
1347 safety_state_ = updated_value;
[email protected]a6e12012012-02-08 02:24:081348 bound_net_log_.AddEvent(
1349 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
[email protected]35869622012-10-26 23:23:551350 base::Bind(&ItemCheckedNetLogCallback, GetDangerType(),
1351 GetSafetyState()));
[email protected]c09a8fd2011-11-21 19:54:501352 }
1353}
1354
[email protected]3d833de2012-05-30 23:32:061355void DownloadItemImpl::SetFullPath(const FilePath& new_path) {
[email protected]0634626a2012-05-03 19:04:261356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3d833de2012-05-30 23:32:061357 VLOG(20) << __FUNCTION__ << "()"
1358 << " new_path = \"" << new_path.value() << "\""
1359 << " " << DebugString(true);
1360 DCHECK(!new_path.empty());
[email protected]c09a8fd2011-11-21 19:54:501361
[email protected]3d833de2012-05-30 23:32:061362 bound_net_log_.AddEvent(
1363 net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED,
[email protected]35869622012-10-26 23:23:551364 base::Bind(&ItemRenamedNetLogCallback, &current_path_, &new_path));
[email protected]6313d142012-11-26 23:13:421365
1366 current_path_ = new_path;
1367 UpdateObservers();
[email protected]c09a8fd2011-11-21 19:54:501368}
1369
[email protected]d0d368252012-09-24 17:13:421370// static
1371DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
1372 DownloadInternalState internal_state) {
1373 switch (internal_state) {
1374 case IN_PROGRESS_INTERNAL:
1375 return IN_PROGRESS;
1376 case COMPLETING_INTERNAL:
1377 return IN_PROGRESS;
1378 case COMPLETE_INTERNAL:
1379 return COMPLETE;
1380 case CANCELLED_INTERNAL:
1381 return CANCELLED;
1382 case INTERRUPTED_INTERNAL:
1383 return INTERRUPTED;
1384 default:
1385 NOTREACHED();
1386 }
1387 return MAX_DOWNLOAD_STATE;
1388}
[email protected]5009b7a2012-02-21 18:47:031389
[email protected]d0d368252012-09-24 17:13:421390// static
1391DownloadItemImpl::DownloadInternalState
1392DownloadItemImpl::ExternalToInternalState(
1393 DownloadState external_state) {
1394 switch (external_state) {
1395 case IN_PROGRESS:
1396 return IN_PROGRESS_INTERNAL;
1397 case COMPLETE:
1398 return COMPLETE_INTERNAL;
1399 case CANCELLED:
1400 return CANCELLED_INTERNAL;
1401 case INTERRUPTED:
1402 return INTERRUPTED_INTERNAL;
1403 default:
1404 NOTREACHED();
1405 }
1406 return MAX_DOWNLOAD_INTERNAL_STATE;
1407 }
[email protected]a6e12012012-02-08 02:24:081408
[email protected]d0d368252012-09-24 17:13:421409const char* DownloadItemImpl::DebugDownloadStateString(
1410 DownloadInternalState state) {
1411 switch (state) {
1412 case IN_PROGRESS_INTERNAL:
1413 return "IN_PROGRESS";
1414 case COMPLETING_INTERNAL:
1415 return "COMPLETING";
1416 case COMPLETE_INTERNAL:
1417 return "COMPLETE";
1418 case CANCELLED_INTERNAL:
1419 return "CANCELLED";
1420 case INTERRUPTED_INTERNAL:
1421 return "INTERRUPTED";
1422 default:
1423 NOTREACHED() << "Unknown download state " << state;
1424 return "unknown";
1425 };
1426}
[email protected]35869622012-10-26 23:23:551427
1428} // namespace content