1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // 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
7 // 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.
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
24 #include "content/browser/download/download_item_impl.h"
28 #include "base/basictypes.h"
29 #include "base/bind.h"
30 #include "base/command_line.h"
31 #include "base/file_util.h"
32 #include "base/format_macros.h"
33 #include "base/logging.h"
34 #include "base/metrics/histogram.h"
35 #include "base/stl_util.h"
36 #include "base/strings/stringprintf.h"
37 #include "base/strings/utf_string_conversions.h"
38 #include "content/browser/download/download_create_info.h"
39 #include "content/browser/download/download_file.h"
40 #include "content/browser/download/download_interrupt_reasons_impl.h"
41 #include "content/browser/download/download_item_impl_delegate.h"
42 #include "content/browser/download/download_request_handle.h"
43 #include "content/browser/download/download_stats.h"
44 #include "content/browser/renderer_host/render_view_host_impl.h"
45 #include "content/browser/web_contents/web_contents_impl.h"
46 #include "content/public/browser/browser_context.h"
47 #include "content/public/browser/browser_thread.h"
48 #include "content/public/browser/content_browser_client.h"
49 #include "content/public/browser/download_danger_type.h"
50 #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"
54 #include "net/base/net_util.h"
60 void DeleteDownloadedFile(const base::FilePath& path) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
63 // Make sure we only delete files.
64 if (!base::DirectoryExists(path))
65 base::DeleteFile(path, false);
68 // Wrapper around DownloadFile::Detach and DownloadFile::Cancel that
69 // takes ownership of the DownloadFile and hence implicitly destroys it
70 // at the end of the function.
71 static base::FilePath DownloadFileDetach(
72 scoped_ptr<DownloadFile> download_file) {
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
74 base::FilePath full_path = download_file->FullPath();
75 download_file->Detach();
79 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
81 download_file->Cancel();
84 bool IsDownloadResumptionEnabled() {
85 return CommandLine::ForCurrentProcess()->HasSwitch(
86 switches::kEnableDownloadResumption);
91 const uint32 DownloadItem::kInvalidId = 0;
93 const char DownloadItem::kEmptyFileHash[] = "";
95 // The maximum number of attempts we will make to resume automatically.
96 const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
98 // Constructor for reading from the history service.
99 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
101 const base::FilePath& current_path,
102 const base::FilePath& target_path,
103 const std::vector<GURL>& url_chain,
104 const GURL& referrer_url,
105 const base::Time& start_time,
106 const base::Time& end_time,
107 const std::string& etag,
108 const std::string& last_modified,
109 int64 received_bytes,
111 DownloadItem::DownloadState state,
112 DownloadDangerType danger_type,
113 DownloadInterruptReason interrupt_reason,
115 const net::BoundNetLog& bound_net_log)
116 : is_save_package_download_(false),
117 download_id_(download_id),
118 current_path_(current_path),
119 target_path_(target_path),
120 target_disposition_(TARGET_DISPOSITION_OVERWRITE),
121 url_chain_(url_chain),
122 referrer_url_(referrer_url),
123 transition_type_(PAGE_TRANSITION_LINK),
124 has_user_gesture_(false),
125 total_bytes_(total_bytes),
126 received_bytes_(received_bytes),
128 last_modified_time_(last_modified),
130 last_reason_(interrupt_reason),
131 start_tick_(base::TimeTicks()),
132 state_(ExternalToInternalState(state)),
133 danger_type_(danger_type),
134 start_time_(start_time),
138 auto_resume_count_(0),
139 open_when_complete_(false),
140 file_externally_removed_(false),
142 is_temporary_(false),
143 all_data_saved_(state == COMPLETE),
144 destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
146 delegate_delayed_complete_(false),
147 bound_net_log_(bound_net_log),
148 weak_ptr_factory_(this) {
150 DCHECK_NE(IN_PROGRESS_INTERNAL, state_);
151 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
154 // Constructing for a regular download:
155 DownloadItemImpl::DownloadItemImpl(
156 DownloadItemImplDelegate* delegate,
158 const DownloadCreateInfo& info,
159 const net::BoundNetLog& bound_net_log)
160 : is_save_package_download_(false),
161 download_id_(download_id),
163 (info.save_info->prompt_for_save_location) ?
164 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE),
165 url_chain_(info.url_chain),
166 referrer_url_(info.referrer_url),
167 suggested_filename_(UTF16ToUTF8(info.save_info->suggested_name)),
168 forced_file_path_(info.save_info->file_path),
169 transition_type_(info.transition_type),
170 has_user_gesture_(info.has_user_gesture),
171 content_disposition_(info.content_disposition),
172 mime_type_(info.mime_type),
173 original_mime_type_(info.original_mime_type),
174 remote_address_(info.remote_address),
175 total_bytes_(info.total_bytes),
178 last_modified_time_(info.last_modified),
180 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
181 start_tick_(base::TimeTicks::Now()),
182 state_(IN_PROGRESS_INTERNAL),
183 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
184 start_time_(info.start_time),
187 auto_resume_count_(0),
188 open_when_complete_(false),
189 file_externally_removed_(false),
191 is_temporary_(!info.save_info->file_path.empty()),
192 all_data_saved_(false),
193 destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
195 delegate_delayed_complete_(false),
196 bound_net_log_(bound_net_log),
197 weak_ptr_factory_(this) {
199 Init(true /* actively downloading */, SRC_ACTIVE_DOWNLOAD);
201 // Link the event sources.
202 bound_net_log_.AddEvent(
203 net::NetLog::TYPE_DOWNLOAD_URL_REQUEST,
204 info.request_bound_net_log.source().ToEventParametersCallback());
206 info.request_bound_net_log.AddEvent(
207 net::NetLog::TYPE_DOWNLOAD_STARTED,
208 bound_net_log_.source().ToEventParametersCallback());
211 // Constructing for the "Save Page As..." feature:
212 DownloadItemImpl::DownloadItemImpl(
213 DownloadItemImplDelegate* delegate,
215 const base::FilePath& path,
217 const std::string& mime_type,
218 scoped_ptr<DownloadRequestHandleInterface> request_handle,
219 const net::BoundNetLog& bound_net_log)
220 : is_save_package_download_(true),
221 request_handle_(request_handle.Pass()),
222 download_id_(download_id),
225 target_disposition_(TARGET_DISPOSITION_OVERWRITE),
227 referrer_url_(GURL()),
228 transition_type_(PAGE_TRANSITION_LINK),
229 has_user_gesture_(false),
230 mime_type_(mime_type),
231 original_mime_type_(mime_type),
235 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
236 start_tick_(base::TimeTicks::Now()),
237 state_(IN_PROGRESS_INTERNAL),
238 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
239 start_time_(base::Time::Now()),
242 auto_resume_count_(0),
243 open_when_complete_(false),
244 file_externally_removed_(false),
246 is_temporary_(false),
247 all_data_saved_(false),
248 destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
250 delegate_delayed_complete_(false),
251 bound_net_log_(bound_net_log),
252 weak_ptr_factory_(this) {
254 Init(true /* actively downloading */, SRC_SAVE_PAGE_AS);
257 DownloadItemImpl::~DownloadItemImpl() {
258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
260 // Should always have been nuked before now, at worst in
261 // DownloadManager shutdown.
262 DCHECK(!download_file_.get());
264 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
265 delegate_->AssertStateConsistent(this);
269 void DownloadItemImpl::AddObserver(Observer* observer) {
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
272 observers_.AddObserver(observer);
275 void DownloadItemImpl::RemoveObserver(Observer* observer) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
278 observers_.RemoveObserver(observer);
281 void DownloadItemImpl::UpdateObservers() {
282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
284 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
287 void DownloadItemImpl::ValidateDangerousDownload() {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
290 DCHECK(IsDangerous());
292 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
294 if (IsDone() || !IsDangerous())
297 RecordDangerousDownloadAccept(GetDangerType(),
298 GetTargetFilePath());
300 danger_type_ = DOWNLOAD_DANGER_TYPE_USER_VALIDATED;
302 bound_net_log_.AddEvent(
303 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
304 base::Bind(&ItemCheckedNetLogCallback, GetDangerType()));
308 MaybeCompleteDownload();
311 void DownloadItemImpl::StealDangerousDownload(
312 const AcquireFileCallback& callback) {
313 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
315 DCHECK(IsDangerous());
316 if (download_file_) {
317 BrowserThread::PostTaskAndReplyWithResult(
320 base::Bind(&DownloadFileDetach, base::Passed(&download_file_)),
323 callback.Run(current_path_);
325 current_path_.clear();
327 // We have now been deleted.
330 void DownloadItemImpl::Pause() {
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
333 // Ignore irrelevant states.
334 if (state_ != IN_PROGRESS_INTERNAL || is_paused_)
337 request_handle_->PauseRequest();
342 void DownloadItemImpl::Resume() {
343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
345 case IN_PROGRESS_INTERNAL:
348 request_handle_->ResumeRequest();
353 case COMPLETING_INTERNAL:
354 case COMPLETE_INTERNAL:
355 case CANCELLED_INTERNAL:
356 case RESUMING_INTERNAL:
359 case INTERRUPTED_INTERNAL:
360 auto_resume_count_ = 0; // User input resets the counter.
361 ResumeInterruptedDownload();
364 case MAX_DOWNLOAD_INTERNAL_STATE:
369 void DownloadItemImpl::Cancel(bool user_cancel) {
370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
372 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
373 if (state_ != IN_PROGRESS_INTERNAL &&
374 state_ != INTERRUPTED_INTERNAL &&
375 state_ != RESUMING_INTERNAL) {
376 // Small downloads might be complete before this method has a chance to run.
381 RecordDangerousDownloadDiscard(
382 user_cancel ? DOWNLOAD_DISCARD_DUE_TO_USER_ACTION
383 : DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN,
385 GetTargetFilePath());
388 last_reason_ = user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
389 : DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
391 RecordDownloadCount(CANCELLED_COUNT);
393 // TODO(rdsmith/benjhayden): Remove condition as part of
394 // |SavePackage| integration.
395 // |download_file_| can be NULL if Interrupt() is called after the
396 // download file has been released.
397 if (!is_save_package_download_ && download_file_)
398 ReleaseDownloadFile(true);
400 if (state_ == IN_PROGRESS_INTERNAL) {
401 // Cancel the originating URL request unless it's already been cancelled
403 request_handle_->CancelRequest();
406 // Remove the intermediate file if we are cancelling an interrupted download.
407 // Continuable interruptions leave the intermediate file around.
408 if ((state_ == INTERRUPTED_INTERNAL || state_ == RESUMING_INTERNAL) &&
409 !current_path_.empty()) {
410 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
411 base::Bind(&DeleteDownloadedFile, current_path_));
412 current_path_.clear();
415 TransitionTo(CANCELLED_INTERNAL, UPDATE_OBSERVERS);
418 void DownloadItemImpl::Remove() {
419 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
422 delegate_->AssertStateConsistent(this);
424 delegate_->AssertStateConsistent(this);
427 delegate_->DownloadRemoved(this);
428 // We have now been deleted.
431 void DownloadItemImpl::OpenDownload() {
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
435 // We don't honor the open_when_complete_ flag for temporary
436 // downloads. Don't set it because it shows up in the UI.
438 open_when_complete_ = !open_when_complete_;
442 if (state_ != COMPLETE_INTERNAL || file_externally_removed_)
445 // Ideally, we want to detect errors in opening and report them, but we
446 // don't generally have the proper interface for that to the external
447 // program that opens the file. So instead we spawn a check to update
448 // the UI if the file has been deleted in parallel with the open.
449 delegate_->CheckForFileRemoval(this);
450 RecordOpen(GetEndTime(), !GetOpened());
452 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
453 delegate_->OpenDownload(this);
456 void DownloadItemImpl::ShowDownloadInShell() {
457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
459 delegate_->ShowDownloadInShell(this);
462 uint32 DownloadItemImpl::GetId() const {
466 DownloadItem::DownloadState DownloadItemImpl::GetState() const {
467 return InternalToExternalState(state_);
470 DownloadInterruptReason DownloadItemImpl::GetLastReason() const {
474 bool DownloadItemImpl::IsPaused() const {
478 bool DownloadItemImpl::IsTemporary() const {
479 return is_temporary_;
482 bool DownloadItemImpl::CanResume() const {
483 if ((GetState() == IN_PROGRESS) && IsPaused())
486 if (state_ != INTERRUPTED_INTERNAL)
489 // Downloads that don't have a WebContents should still be resumable, but this
490 // isn't currently the case. See ResumeInterruptedDownload().
491 if (!GetWebContents())
494 ResumeMode resume_mode = GetResumeMode();
495 return IsDownloadResumptionEnabled() &&
496 (resume_mode == RESUME_MODE_USER_RESTART ||
497 resume_mode == RESUME_MODE_USER_CONTINUE);
500 bool DownloadItemImpl::IsDone() const {
502 case IN_PROGRESS_INTERNAL:
503 case COMPLETING_INTERNAL:
506 case COMPLETE_INTERNAL:
507 case CANCELLED_INTERNAL:
510 case INTERRUPTED_INTERNAL:
513 case RESUMING_INTERNAL:
516 case MAX_DOWNLOAD_INTERNAL_STATE:
523 const GURL& DownloadItemImpl::GetURL() const {
524 return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.back();
527 const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const {
531 const GURL& DownloadItemImpl::GetOriginalUrl() const {
532 // Be careful about taking the front() of possibly-empty vectors!
533 // http://crbug.com/190096
534 return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.front();
537 const GURL& DownloadItemImpl::GetReferrerUrl() const {
538 return referrer_url_;
541 std::string DownloadItemImpl::GetSuggestedFilename() const {
542 return suggested_filename_;
545 std::string DownloadItemImpl::GetContentDisposition() const {
546 return content_disposition_;
549 std::string DownloadItemImpl::GetMimeType() const {
553 std::string DownloadItemImpl::GetOriginalMimeType() const {
554 return original_mime_type_;
557 std::string DownloadItemImpl::GetRemoteAddress() const {
558 return remote_address_;
561 bool DownloadItemImpl::HasUserGesture() const {
562 return has_user_gesture_;
565 PageTransition DownloadItemImpl::GetTransitionType() const {
566 return transition_type_;
569 const std::string& DownloadItemImpl::GetLastModifiedTime() const {
570 return last_modified_time_;
573 const std::string& DownloadItemImpl::GetETag() const {
577 bool DownloadItemImpl::IsSavePackageDownload() const {
578 return is_save_package_download_;
581 const base::FilePath& DownloadItemImpl::GetFullPath() const {
582 return current_path_;
585 const base::FilePath& DownloadItemImpl::GetTargetFilePath() const {
589 const base::FilePath& DownloadItemImpl::GetForcedFilePath() const {
590 // TODO(asanka): Get rid of GetForcedFilePath(). We should instead just
591 // require that clients respect GetTargetFilePath() if it is already set.
592 return forced_file_path_;
595 base::FilePath DownloadItemImpl::GetFileNameToReportUser() const {
596 if (!display_name_.empty())
597 return display_name_;
598 return target_path_.BaseName();
601 DownloadItem::TargetDisposition DownloadItemImpl::GetTargetDisposition() const {
602 return target_disposition_;
605 const std::string& DownloadItemImpl::GetHash() const {
609 const std::string& DownloadItemImpl::GetHashState() const {
613 bool DownloadItemImpl::GetFileExternallyRemoved() const {
614 return file_externally_removed_;
617 void DownloadItemImpl::DeleteFile() {
618 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
619 if ((GetState() != DownloadItem::COMPLETE) ||
620 file_externally_removed_) {
623 BrowserThread::PostTaskAndReply(
624 BrowserThread::FILE, FROM_HERE,
625 base::Bind(&DeleteDownloadedFile, current_path_),
626 base::Bind(&DownloadItemImpl::OnDownloadedFileRemoved,
627 weak_ptr_factory_.GetWeakPtr()));
628 current_path_.clear();
631 bool DownloadItemImpl::IsDangerous() const {
633 // TODO(noelutz): At this point only the windows views UI supports
634 // warnings based on dangerous content.
635 return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
636 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
637 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
638 danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
639 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
640 danger_type_ == DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
642 return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
643 danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
647 DownloadDangerType DownloadItemImpl::GetDangerType() const {
651 bool DownloadItemImpl::TimeRemaining(base::TimeDelta* remaining) const {
652 if (total_bytes_ <= 0)
653 return false; // We never received the content_length for this download.
655 int64 speed = CurrentSpeed();
659 *remaining = base::TimeDelta::FromSeconds(
660 (total_bytes_ - received_bytes_) / speed);
664 int64 DownloadItemImpl::CurrentSpeed() const {
667 return bytes_per_sec_;
670 int DownloadItemImpl::PercentComplete() const {
671 // If the delegate is delaying completion of the download, then we have no
672 // idea how long it will take.
673 if (delegate_delayed_complete_ || total_bytes_ <= 0)
676 return static_cast<int>(received_bytes_ * 100.0 / total_bytes_);
679 bool DownloadItemImpl::AllDataSaved() const {
680 return all_data_saved_;
683 int64 DownloadItemImpl::GetTotalBytes() const {
687 int64 DownloadItemImpl::GetReceivedBytes() const {
688 return received_bytes_;
691 base::Time DownloadItemImpl::GetStartTime() const {
695 base::Time DownloadItemImpl::GetEndTime() const {
699 bool DownloadItemImpl::CanShowInFolder() {
700 // A download can be shown in the folder if the downloaded file is in a known
702 return CanOpenDownload() && !GetFullPath().empty();
705 bool DownloadItemImpl::CanOpenDownload() {
706 // We can open the file or mark it for opening on completion if the download
707 // is expected to complete successfully. Exclude temporary downloads, since
708 // they aren't owned by the download system.
709 const bool is_complete = GetState() == DownloadItem::COMPLETE;
710 return (!IsDone() || is_complete) && !IsTemporary() &&
711 !file_externally_removed_;
714 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
715 return delegate_->ShouldOpenFileBasedOnExtension(GetTargetFilePath());
718 bool DownloadItemImpl::GetOpenWhenComplete() const {
719 return open_when_complete_;
722 bool DownloadItemImpl::GetAutoOpened() {
726 bool DownloadItemImpl::GetOpened() const {
730 BrowserContext* DownloadItemImpl::GetBrowserContext() const {
731 return delegate_->GetBrowserContext();
734 WebContents* DownloadItemImpl::GetWebContents() const {
735 // TODO(rdsmith): Remove null check after removing GetWebContents() from
736 // paths that might be used by DownloadItems created from history import.
737 // Currently such items have null request_handle_s, where other items
738 // (regular and SavePackage downloads) have actual objects off the pointer.
740 return request_handle_->GetWebContents();
744 void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) {
745 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
746 DCHECK(AllDataSaved());
747 VLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
748 << " download=" << DebugString(true);
749 SetDangerType(danger_type);
753 void DownloadItemImpl::SetOpenWhenComplete(bool open) {
754 open_when_complete_ = open;
757 void DownloadItemImpl::SetIsTemporary(bool temporary) {
758 is_temporary_ = temporary;
761 void DownloadItemImpl::SetOpened(bool opened) {
765 void DownloadItemImpl::SetDisplayName(const base::FilePath& name) {
766 display_name_ = name;
769 std::string DownloadItemImpl::DebugString(bool verbose) const {
770 std::string description =
771 base::StringPrintf("{ id = %d"
774 DebugDownloadStateString(state_));
776 // Construct a string of the URL chain.
777 std::string url_list("<none>");
778 if (!url_chain_.empty()) {
779 std::vector<GURL>::const_iterator iter = url_chain_.begin();
780 std::vector<GURL>::const_iterator last = url_chain_.end();
781 url_list = (*iter).is_valid() ? (*iter).spec() : "<invalid>";
783 for ( ; verbose && (iter != last); ++iter) {
784 url_list += " ->\n\t";
785 const GURL& next_url = *iter;
786 url_list += next_url.is_valid() ? next_url.spec() : "<invalid>";
791 description += base::StringPrintf(
793 " received = %" PRId64
797 " auto_resume_count = %d"
799 " all_data_saved = %c"
800 " last_modified = '%s'"
802 " has_download_file = %s"
803 " url_chain = \n\t\"%s\"\n\t"
804 " full_path = \"%" PRFilePath "\"\n\t"
805 " target_path = \"%" PRFilePath "\"",
808 InterruptReasonDebugString(last_reason_).c_str(),
809 IsPaused() ? 'T' : 'F',
810 DebugResumeModeString(GetResumeMode()),
813 AllDataSaved() ? 'T' : 'F',
814 GetLastModifiedTime().c_str(),
816 download_file_.get() ? "true" : "false",
818 GetFullPath().value().c_str(),
819 GetTargetFilePath().value().c_str());
821 description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
829 DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
830 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
831 // We can't continue without a handle on the intermediate file.
832 // We also can't continue if we don't have some verifier to make sure
833 // we're getting the same file.
834 const bool force_restart =
835 (current_path_.empty() || (etag_.empty() && last_modified_time_.empty()));
837 // We won't auto-restart if we've used up our attempts or the
838 // download has been paused by user action.
839 const bool force_user =
840 (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_);
842 ResumeMode mode = RESUME_MODE_INVALID;
844 switch(last_reason_) {
845 case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
846 case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
847 if (force_restart && force_user)
848 mode = RESUME_MODE_USER_RESTART;
849 else if (force_restart)
850 mode = RESUME_MODE_IMMEDIATE_RESTART;
852 mode = RESUME_MODE_USER_CONTINUE;
854 mode = RESUME_MODE_IMMEDIATE_CONTINUE;
857 case DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
858 case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
859 case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
861 mode = RESUME_MODE_USER_RESTART;
863 mode = RESUME_MODE_IMMEDIATE_RESTART;
866 case DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
867 case DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
868 case DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
869 case DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
870 case DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
871 case DOWNLOAD_INTERRUPT_REASON_CRASH:
873 mode = RESUME_MODE_USER_RESTART;
875 mode = RESUME_MODE_USER_CONTINUE;
878 case DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
879 case DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
880 case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
881 case DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
882 case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
883 mode = RESUME_MODE_USER_RESTART;
886 case DOWNLOAD_INTERRUPT_REASON_NONE:
887 case DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
888 case DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
889 case DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
890 case DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
891 case DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
892 mode = RESUME_MODE_INVALID;
899 void DownloadItemImpl::NotifyRemoved() {
900 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
903 void DownloadItemImpl::OnDownloadedFileRemoved() {
904 file_externally_removed_ = true;
905 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
909 base::WeakPtr<DownloadDestinationObserver>
910 DownloadItemImpl::DestinationObserverAsWeakPtr() {
911 return weak_ptr_factory_.GetWeakPtr();
914 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
915 return bound_net_log_;
918 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
919 total_bytes_ = total_bytes;
922 void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
923 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
925 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
926 DCHECK(!all_data_saved_);
927 all_data_saved_ = true;
928 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
930 // Store final hash and null out intermediate serialized hash state.
937 void DownloadItemImpl::MarkAsComplete() {
938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
940 DCHECK(all_data_saved_);
941 end_time_ = base::Time::Now();
942 TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
945 void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far,
947 const std::string& hash_state) {
948 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
949 VLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
950 << " per_sec=" << bytes_per_sec << " download=" << DebugString(true);
952 if (GetState() != IN_PROGRESS) {
953 // Ignore if we're no longer in-progress. This can happen if we race a
954 // Cancel on the UI thread with an update on the FILE thread.
956 // TODO(rdsmith): Arguably we should let this go through, as this means
957 // the download really did get further than we know before it was
958 // cancelled. But the gain isn't very large, and the code is more
959 // fragile if it has to support in progress updates in a non-in-progress
960 // state. This issue should be readdressed when we revamp performance
964 bytes_per_sec_ = bytes_per_sec;
965 hash_state_ = hash_state;
966 received_bytes_ = bytes_so_far;
968 // If we've received more data than we were expecting (bad server info?),
969 // revert to 'unknown size mode'.
970 if (received_bytes_ > total_bytes_)
973 if (bound_net_log_.IsLoggingAllEvents()) {
974 bound_net_log_.AddEvent(
975 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
976 net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
982 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
983 // Postpone recognition of this error until after file name determination
984 // has completed and the intermediate file has been renamed to simplify
985 // resumption conditions.
986 if (current_path_.empty() || target_path_.empty())
987 destination_error_ = reason;
992 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
993 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
994 if (GetState() != IN_PROGRESS)
996 OnAllDataSaved(final_hash);
997 MaybeCompleteDownload();
1000 // **** Download progression cascade
1002 void DownloadItemImpl::Init(bool active,
1003 DownloadType download_type) {
1004 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1007 RecordDownloadCount(START_COUNT);
1009 std::string file_name;
1010 if (download_type == SRC_HISTORY_IMPORT) {
1011 // target_path_ works for History and Save As versions.
1012 file_name = target_path_.AsUTF8Unsafe();
1014 // See if it's set programmatically.
1015 file_name = forced_file_path_.AsUTF8Unsafe();
1016 // Possibly has a 'download' attribute for the anchor.
1017 if (file_name.empty())
1018 file_name = suggested_filename_;
1019 // From the URL file name.
1020 if (file_name.empty())
1021 file_name = GetURL().ExtractFileName();
1024 base::Callback<base::Value*(net::NetLog::LogLevel)> active_data = base::Bind(
1025 &ItemActivatedNetLogCallback, this, download_type, &file_name);
1027 bound_net_log_.BeginEvent(
1028 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
1030 bound_net_log_.AddEvent(
1031 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
1034 VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
1037 // We're starting the download.
1038 void DownloadItemImpl::Start(
1039 scoped_ptr<DownloadFile> file,
1040 scoped_ptr<DownloadRequestHandleInterface> req_handle) {
1041 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1042 DCHECK(!download_file_.get());
1044 DCHECK(req_handle.get());
1046 download_file_ = file.Pass();
1047 request_handle_ = req_handle.Pass();
1049 if (GetState() == CANCELLED) {
1050 // The download was in the process of resuming when it was cancelled. Don't
1052 ReleaseDownloadFile(true);
1053 request_handle_->CancelRequest();
1057 TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS);
1059 BrowserThread::PostTask(
1060 BrowserThread::FILE, FROM_HERE,
1061 base::Bind(&DownloadFile::Initialize,
1062 // Safe because we control download file lifetime.
1063 base::Unretained(download_file_.get()),
1064 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
1065 weak_ptr_factory_.GetWeakPtr())));
1068 void DownloadItemImpl::OnDownloadFileInitialized(
1069 DownloadInterruptReason result) {
1070 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1071 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
1073 // TODO(rdsmith/asanka): Arguably we should show this in the UI, but
1074 // it's not at all clear what to show--we haven't done filename
1075 // determination, so we don't know what name to display. OTOH,
1076 // the failure mode of not showing the DI if the file initialization
1077 // fails isn't a good one. Can we hack up a name based on the
1078 // URLRequest? We'll need to make sure that initialization happens
1079 // properly. Possibly the right thing is to have the UI handle
1080 // this case specially.
1084 delegate_->DetermineDownloadTarget(
1085 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
1086 weak_ptr_factory_.GetWeakPtr()));
1089 // Called by delegate_ when the download target path has been
1091 void DownloadItemImpl::OnDownloadTargetDetermined(
1092 const base::FilePath& target_path,
1093 TargetDisposition disposition,
1094 DownloadDangerType danger_type,
1095 const base::FilePath& intermediate_path) {
1096 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1098 // If the |target_path| is empty, then we consider this download to be
1100 if (target_path.empty()) {
1105 // TODO(rdsmith,asanka): We are ignoring the possibility that the download
1106 // has been interrupted at this point until we finish the intermediate
1107 // rename and set the full path. That's dangerous, because we might race
1108 // with resumption, either manual (because the interrupt is visible to the
1109 // UI) or automatic. If we keep the "ignore an error on download until file
1110 // name determination complete" semantics, we need to make sure that the
1111 // error is kept completely invisible until that point.
1113 VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
1114 << " " << danger_type << " " << DebugString(true);
1116 target_path_ = target_path;
1117 target_disposition_ = disposition;
1118 SetDangerType(danger_type);
1120 // We want the intermediate and target paths to refer to the same directory so
1121 // that they are both on the same device and subject to same
1122 // space/permission/availability constraints.
1123 DCHECK(intermediate_path.DirName() == target_path.DirName());
1125 // During resumption, we may choose to proceed with the same intermediate
1126 // file. No rename is necessary if our intermediate file already has the
1129 // The intermediate name may change from its original value during filename
1130 // determination on resumption, for example if the reason for the interruption
1131 // was the download target running out space, resulting in a user prompt.
1132 if (intermediate_path == current_path_) {
1133 OnDownloadRenamedToIntermediateName(DOWNLOAD_INTERRUPT_REASON_NONE,
1138 // Rename to intermediate name.
1139 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
1140 // spurious rename when we can just rename to the final
1141 // filename. Unnecessary renames may cause bugs like
1142 // http://crbug.com/74187.
1143 DCHECK(!is_save_package_download_);
1144 DCHECK(download_file_.get());
1145 DownloadFile::RenameCompletionCallback callback =
1146 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
1147 weak_ptr_factory_.GetWeakPtr());
1148 BrowserThread::PostTask(
1149 BrowserThread::FILE, FROM_HERE,
1150 base::Bind(&DownloadFile::RenameAndUniquify,
1151 // Safe because we control download file lifetime.
1152 base::Unretained(download_file_.get()),
1153 intermediate_path, callback));
1156 void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
1157 DownloadInterruptReason reason,
1158 const base::FilePath& full_path) {
1159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1160 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
1162 if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) {
1163 // Process destination error. If both |reason| and |destination_error_|
1164 // refer to actual errors, we want to use the |destination_error_| as the
1165 // argument to the Interrupt() routine, as it happened first.
1166 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE)
1167 SetFullPath(full_path);
1168 Interrupt(destination_error_);
1169 destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
1170 } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
1172 // All file errors result in file deletion above; no need to cleanup. The
1173 // current_path_ should be empty. Resuming this download will force a
1174 // restart and a re-doing of filename determination.
1175 DCHECK(current_path_.empty());
1177 SetFullPath(full_path);
1179 MaybeCompleteDownload();
1183 // When SavePackage downloads MHTML to GData (see
1184 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
1185 // does for non-SavePackage downloads, but SavePackage downloads never satisfy
1186 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
1187 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage
1188 // notices that the upload has completed and runs its normal Finish() pathway.
1189 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes
1190 // downloads. SavePackage always uses its own Finish() to mark downloads
1192 void DownloadItemImpl::MaybeCompleteDownload() {
1193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1194 DCHECK(!is_save_package_download_);
1196 if (!IsDownloadReadyForCompletion(
1197 base::Bind(&DownloadItemImpl::MaybeCompleteDownload,
1198 weak_ptr_factory_.GetWeakPtr())))
1201 // TODO(rdsmith): DCHECK that we only pass through this point
1202 // once per download. The natural way to do this is by a state
1203 // transition on the DownloadItem.
1205 // Confirm we're in the proper set of states to be here;
1206 // have all data, have a history handle, (validated or safe).
1207 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
1208 DCHECK(!IsDangerous());
1209 DCHECK(all_data_saved_);
1211 OnDownloadCompleting();
1214 // Called by MaybeCompleteDownload() when it has determined that the download
1215 // is ready for completion.
1216 void DownloadItemImpl::OnDownloadCompleting() {
1217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1219 if (state_ != IN_PROGRESS_INTERNAL)
1222 VLOG(20) << __FUNCTION__ << "()"
1223 << " " << DebugString(true);
1224 DCHECK(!GetTargetFilePath().empty());
1225 DCHECK(!IsDangerous());
1227 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
1228 if (is_save_package_download_) {
1229 // Avoid doing anything on the file thread; there's nothing we control
1231 // Strictly speaking, this skips giving the embedder a chance to open
1232 // the download. But on a save package download, there's no real
1233 // concept of opening.
1238 DCHECK(download_file_.get());
1239 // Unilaterally rename; even if it already has the right name,
1240 // we need theannotation.
1241 DownloadFile::RenameCompletionCallback callback =
1242 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName,
1243 weak_ptr_factory_.GetWeakPtr());
1244 BrowserThread::PostTask(
1245 BrowserThread::FILE, FROM_HERE,
1246 base::Bind(&DownloadFile::RenameAndAnnotate,
1247 base::Unretained(download_file_.get()),
1248 GetTargetFilePath(), callback));
1251 void DownloadItemImpl::OnDownloadRenamedToFinalName(
1252 DownloadInterruptReason reason,
1253 const base::FilePath& full_path) {
1254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1255 DCHECK(!is_save_package_download_);
1257 // If a cancel or interrupt hit, we'll cancel the DownloadFile, which
1258 // will result in deleting the file on the file thread. So we don't
1259 // care about the name having been changed.
1260 if (state_ != IN_PROGRESS_INTERNAL)
1263 VLOG(20) << __FUNCTION__ << "()"
1264 << " full_path = \"" << full_path.value() << "\""
1265 << " " << DebugString(false);
1267 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
1270 // All file errors should have resulted in in file deletion above. On
1271 // resumption we will need to re-do filename determination.
1272 DCHECK(current_path_.empty());
1276 DCHECK(target_path_ == full_path);
1278 if (full_path != current_path_) {
1279 // full_path is now the current and target file path.
1280 DCHECK(!full_path.empty());
1281 SetFullPath(full_path);
1284 // Complete the download and release the DownloadFile.
1285 DCHECK(download_file_.get());
1286 ReleaseDownloadFile(false);
1288 // We're not completely done with the download item yet, but at this
1289 // point we're committed to complete the download. Cancels (or Interrupts,
1290 // though it's not clear how they could happen) after this point will be
1292 TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS);
1294 if (delegate_->ShouldOpenDownload(
1295 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened,
1296 weak_ptr_factory_.GetWeakPtr()))) {
1299 delegate_delayed_complete_ = true;
1304 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
1305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1307 auto_opened_ = auto_opened;
1311 void DownloadItemImpl::Completed() {
1312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1314 VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
1316 DCHECK(all_data_saved_);
1317 end_time_ = base::Time::Now();
1318 TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
1319 RecordDownloadCompleted(start_tick_, received_bytes_);
1322 // If it was already handled by the delegate, do nothing.
1323 } else if (GetOpenWhenComplete() ||
1324 ShouldOpenFileBasedOnExtension() ||
1326 // If the download is temporary, like in drag-and-drop, do not open it but
1327 // we still need to set it auto-opened so that it can be removed from the
1332 auto_opened_ = true;
1337 void DownloadItemImpl::OnResumeRequestStarted(DownloadItem* item,
1339 // If |item| is not NULL, then Start() has been called already, and nothing
1340 // more needs to be done here.
1342 DCHECK_EQ(net::OK, error);
1343 DCHECK_EQ(static_cast<DownloadItem*>(this), item);
1346 // Otherwise, the request failed without passing through
1347 // DownloadResourceHandler::OnResponseStarted.
1348 if (error == net::OK)
1349 error = net::ERR_FAILED;
1350 DownloadInterruptReason reason =
1351 ConvertNetErrorToInterruptReason(error, DOWNLOAD_INTERRUPT_FROM_NETWORK);
1352 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
1356 // **** End of Download progression cascade
1358 // An error occurred somewhere.
1359 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
1360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1362 // Somewhat counter-intuitively, it is possible for us to receive an
1363 // interrupt after we've already been interrupted. The generation of
1364 // interrupts from the file thread Renames and the generation of
1365 // interrupts from disk writes go through two different mechanisms (driven
1366 // by rename requests from UI thread and by write requests from IO thread,
1367 // respectively), and since we choose not to keep state on the File thread,
1368 // this is the place where the races collide. It's also possible for
1369 // interrupts to race with cancels.
1371 // Whatever happens, the first one to hit the UI thread wins.
1372 if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL)
1375 last_reason_ = reason;
1377 ResumeMode resume_mode = GetResumeMode();
1379 if (state_ == IN_PROGRESS_INTERNAL) {
1380 // Cancel (delete file) if we're going to restart; no point in leaving
1381 // data around we aren't going to use. Also cancel if resumption isn't
1382 // enabled for the same reason.
1383 ReleaseDownloadFile(resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
1384 resume_mode == RESUME_MODE_USER_RESTART ||
1385 !IsDownloadResumptionEnabled());
1387 // Cancel the originating URL request.
1388 request_handle_->CancelRequest();
1390 DCHECK(!download_file_.get());
1393 // Reset all data saved, as even if we did save all the data we're going
1394 // to go through another round of downloading when we resume.
1395 // There's a potential problem here in the abstract, as if we did download
1396 // all the data and then run into a continuable error, on resumption we
1397 // won't download any more data. However, a) there are currently no
1398 // continuable errors that can occur after we download all the data, and
1399 // b) if there were, that would probably simply result in a null range
1400 // request, which would generate a DestinationCompleted() notification
1401 // from the DownloadFile, which would behave properly with setting
1402 // all_data_saved_ to false here.
1403 all_data_saved_ = false;
1405 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS);
1406 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
1407 if (!GetWebContents())
1408 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
1410 AutoResumeIfValid();
1414 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
1415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1418 BrowserThread::PostTask(
1419 BrowserThread::FILE, FROM_HERE,
1420 // Will be deleted at end of task execution.
1421 base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
1422 // Avoid attempting to reuse the intermediate file by clearing out
1424 current_path_.clear();
1426 BrowserThread::PostTask(
1427 BrowserThread::FILE,
1429 base::Bind(base::IgnoreResult(&DownloadFileDetach),
1430 // Will be deleted at end of task execution.
1431 base::Passed(&download_file_)));
1433 // Don't accept any more messages from the DownloadFile, and null
1434 // out any previous "all data received". This also breaks links to
1435 // other entities we've given out weak pointers to.
1436 weak_ptr_factory_.InvalidateWeakPtrs();
1439 bool DownloadItemImpl::IsDownloadReadyForCompletion(
1440 const base::Closure& state_change_notification) {
1441 // If we don't have all the data, the download is not ready for
1443 if (!AllDataSaved())
1446 // If the download is dangerous, but not yet validated, it's not ready for
1451 // If the download isn't active (e.g. has been cancelled) it's not
1452 // ready for completion.
1453 if (state_ != IN_PROGRESS_INTERNAL)
1456 // If the target filename hasn't been determined, then it's not ready for
1457 // completion. This is checked in ReadyForDownloadCompletionDone().
1458 if (GetTargetFilePath().empty())
1461 // This is checked in NeedsRename(). Without this conditional,
1462 // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK.
1463 if (target_path_.DirName() != current_path_.DirName())
1466 // Give the delegate a chance to hold up a stop sign. It'll call
1467 // use back through the passed callback if it does and that state changes.
1468 if (!delegate_->ShouldCompleteDownload(this, state_change_notification))
1474 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
1475 ShouldUpdateObservers notify_action) {
1476 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1478 if (state_ == new_state)
1481 DownloadInternalState old_state = state_;
1485 case COMPLETING_INTERNAL:
1486 bound_net_log_.AddEvent(
1487 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
1488 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
1490 case COMPLETE_INTERNAL:
1491 bound_net_log_.AddEvent(
1492 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
1493 base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
1495 case INTERRUPTED_INTERNAL:
1496 bound_net_log_.AddEvent(
1497 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
1498 base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
1499 received_bytes_, &hash_state_));
1501 case IN_PROGRESS_INTERNAL:
1502 if (old_state == INTERRUPTED_INTERNAL) {
1503 bound_net_log_.AddEvent(
1504 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
1505 base::Bind(&ItemResumingNetLogCallback,
1506 false, last_reason_, received_bytes_, &hash_state_));
1509 case CANCELLED_INTERNAL:
1510 bound_net_log_.AddEvent(
1511 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
1512 base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
1519 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
1520 << " " << InternalToExternalState(old_state)
1521 << " " << InternalToExternalState(state_);
1523 bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
1524 state_ != COMPLETING_INTERNAL);
1525 bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
1526 old_state != COMPLETING_INTERNAL);
1528 if (is_done && !was_done)
1529 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
1532 if (was_done && !is_done) {
1533 std::string file_name(target_path_.BaseName().AsUTF8Unsafe());
1534 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
1535 base::Bind(&ItemActivatedNetLogCallback,
1536 this, SRC_ACTIVE_DOWNLOAD,
1540 if (notify_action == UPDATE_OBSERVERS)
1544 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
1545 if (danger_type != danger_type_) {
1546 bound_net_log_.AddEvent(
1547 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
1548 base::Bind(&ItemCheckedNetLogCallback, danger_type));
1550 danger_type_ = danger_type;
1553 void DownloadItemImpl::SetFullPath(const base::FilePath& new_path) {
1554 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1555 VLOG(20) << __FUNCTION__ << "()"
1556 << " new_path = \"" << new_path.value() << "\""
1557 << " " << DebugString(true);
1558 DCHECK(!new_path.empty());
1560 bound_net_log_.AddEvent(
1561 net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED,
1562 base::Bind(&ItemRenamedNetLogCallback, ¤t_path_, &new_path));
1564 current_path_ = new_path;
1567 void DownloadItemImpl::AutoResumeIfValid() {
1568 DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
1569 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1570 ResumeMode mode = GetResumeMode();
1572 if (mode != RESUME_MODE_IMMEDIATE_RESTART &&
1573 mode != RESUME_MODE_IMMEDIATE_CONTINUE) {
1577 auto_resume_count_++;
1579 ResumeInterruptedDownload();
1582 void DownloadItemImpl::ResumeInterruptedDownload() {
1583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1585 // If the flag for downloads resumption isn't enabled, ignore
1587 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1588 if (!command_line.HasSwitch(switches::kEnableDownloadResumption))
1591 // If we're not interrupted, ignore the request; our caller is drunk.
1592 if (state_ != INTERRUPTED_INTERNAL)
1595 // If we can't get a web contents, we can't resume the download.
1596 // TODO(rdsmith): Find some alternative web contents to use--this
1597 // means we can't restart a download if it's a download imported
1598 // from the history.
1599 if (!GetWebContents())
1602 // Reset the appropriate state if restarting.
1603 ResumeMode mode = GetResumeMode();
1604 if (mode == RESUME_MODE_IMMEDIATE_RESTART ||
1605 mode == RESUME_MODE_USER_RESTART) {
1606 received_bytes_ = 0;
1608 last_modified_time_ = "";
1612 scoped_ptr<DownloadUrlParameters> download_params(
1613 DownloadUrlParameters::FromWebContents(GetWebContents(),
1616 download_params->set_file_path(GetFullPath());
1617 download_params->set_offset(GetReceivedBytes());
1618 download_params->set_hash_state(GetHashState());
1619 download_params->set_last_modified(GetLastModifiedTime());
1620 download_params->set_etag(GetETag());
1621 download_params->set_callback(
1622 base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
1623 weak_ptr_factory_.GetWeakPtr()));
1625 delegate_->ResumeInterruptedDownload(download_params.Pass(), GetId());
1626 // Just in case we were interrupted while paused.
1629 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
1633 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
1634 DownloadInternalState internal_state) {
1635 switch (internal_state) {
1636 case IN_PROGRESS_INTERNAL:
1638 case COMPLETING_INTERNAL:
1640 case COMPLETE_INTERNAL:
1642 case CANCELLED_INTERNAL:
1644 case INTERRUPTED_INTERNAL:
1646 case RESUMING_INTERNAL:
1648 case MAX_DOWNLOAD_INTERNAL_STATE:
1652 return MAX_DOWNLOAD_STATE;
1656 DownloadItemImpl::DownloadInternalState
1657 DownloadItemImpl::ExternalToInternalState(
1658 DownloadState external_state) {
1659 switch (external_state) {
1661 return IN_PROGRESS_INTERNAL;
1663 return COMPLETE_INTERNAL;
1665 return CANCELLED_INTERNAL;
1667 return INTERRUPTED_INTERNAL;
1671 return MAX_DOWNLOAD_INTERNAL_STATE;
1674 const char* DownloadItemImpl::DebugDownloadStateString(
1675 DownloadInternalState state) {
1677 case IN_PROGRESS_INTERNAL:
1678 return "IN_PROGRESS";
1679 case COMPLETING_INTERNAL:
1680 return "COMPLETING";
1681 case COMPLETE_INTERNAL:
1683 case CANCELLED_INTERNAL:
1685 case INTERRUPTED_INTERNAL:
1686 return "INTERRUPTED";
1687 case RESUMING_INTERNAL:
1689 case MAX_DOWNLOAD_INTERNAL_STATE:
1692 NOTREACHED() << "Unknown download state " << state;
1696 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
1698 case RESUME_MODE_INVALID:
1700 case RESUME_MODE_IMMEDIATE_CONTINUE:
1701 return "IMMEDIATE_CONTINUE";
1702 case RESUME_MODE_IMMEDIATE_RESTART:
1703 return "IMMEDIATE_RESTART";
1704 case RESUME_MODE_USER_CONTINUE:
1705 return "USER_CONTINUE";
1706 case RESUME_MODE_USER_RESTART:
1707 return "USER_RESTART";
1709 NOTREACHED() << "Unknown resume mode " << mode;
1713 } // namespace content