| Index: content/browser/download/download_item_impl.cc
|
| diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
|
| index ecddd9458c921bdb15e1acbb776e7e5a26baa447..5643698d0e969439f8cfdde8b0663b1b60607b97 100644
|
| --- a/content/browser/download/download_item_impl.cc
|
| +++ b/content/browser/download/download_item_impl.cc
|
| @@ -41,15 +41,21 @@
|
| #include "content/browser/download/download_item_impl_delegate.h"
|
| #include "content/browser/download/download_request_handle.h"
|
| #include "content/browser/download/download_stats.h"
|
| +#include "content/browser/renderer_host/render_view_host_impl.h"
|
| #include "content/browser/web_contents/web_contents_impl.h"
|
| +#include "content/public/browser/browser_context.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "content/public/browser/content_browser_client.h"
|
| +#include "content/public/browser/download_interrupt_reasons.h"
|
| +#include "content/public/browser/download_url_parameters.h"
|
| +#include "content/public/common/referrer.h"
|
| #include "net/base/net_util.h"
|
|
|
| namespace content {
|
| +
|
| namespace {
|
|
|
| -static void DeleteDownloadedFile(const FilePath& path) {
|
| +void DeleteDownloadedFile(const FilePath& path) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
|
|
| // Make sure we only delete files.
|
| @@ -90,6 +96,8 @@ class NullDownloadRequestHandle : public DownloadRequestHandleInterface {
|
| virtual void PauseRequest() const OVERRIDE {}
|
| virtual void ResumeRequest() const OVERRIDE {}
|
| virtual void CancelRequest() const OVERRIDE {}
|
| + virtual void SetRequestId(int new_request_id) OVERRIDE {}
|
| + virtual int RequestId() const OVERRIDE { return -1; }
|
| virtual std::string DebugString() const OVERRIDE {
|
| return "Null DownloadRequestHandle";
|
| }
|
| @@ -112,6 +120,9 @@ static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
|
|
|
| const char DownloadItem::kEmptyFileHash[] = "";
|
|
|
| +// The maximum number of attempts we will make to resume automatically.
|
| +const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
|
| +
|
| // Constructor for reading from the history service.
|
| DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
|
| DownloadId download_id,
|
| @@ -145,6 +156,8 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
|
| end_time_(end_time),
|
| delegate_(delegate),
|
| is_paused_(false),
|
| + is_resuming_(false),
|
| + auto_resume_count_(0),
|
| open_when_complete_(false),
|
| file_externally_removed_(false),
|
| safety_state_(SAFE),
|
| @@ -168,10 +181,8 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
|
| DownloadItemImpl::DownloadItemImpl(
|
| DownloadItemImplDelegate* delegate,
|
| const DownloadCreateInfo& info,
|
| - scoped_ptr<DownloadRequestHandleInterface> request_handle,
|
| const net::BoundNetLog& bound_net_log)
|
| : is_save_package_download_(false),
|
| - request_handle_(request_handle.Pass()),
|
| download_id_(info.download_id),
|
| target_disposition_(
|
| (info.save_info->prompt_for_save_location) ?
|
| @@ -196,6 +207,8 @@ DownloadItemImpl::DownloadItemImpl(
|
| start_time_(info.start_time),
|
| delegate_(delegate),
|
| is_paused_(false),
|
| + is_resuming_(false),
|
| + auto_resume_count_(0),
|
| open_when_complete_(false),
|
| file_externally_removed_(false),
|
| safety_state_(SAFE),
|
| @@ -249,6 +262,8 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
|
| start_time_(base::Time::Now()),
|
| delegate_(delegate),
|
| is_paused_(false),
|
| + is_resuming_(false),
|
| + auto_resume_count_(0),
|
| open_when_complete_(false),
|
| file_externally_removed_(false),
|
| safety_state_(SAFE),
|
| @@ -322,35 +337,41 @@ void DownloadItemImpl::DangerousDownloadValidated() {
|
|
|
| void DownloadItemImpl::TogglePause() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DCHECK(state_ == IN_PROGRESS_INTERNAL || state_ == COMPLETING_INTERNAL);
|
| + DCHECK(IsPartialDownload());
|
| VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
|
|
|
| // Ignore pauses when we've passed the commit point.
|
| if (state_ == COMPLETING_INTERNAL)
|
| return;
|
|
|
| - if (is_paused_)
|
| - request_handle_->ResumeRequest();
|
| - else
|
| - request_handle_->PauseRequest();
|
| - is_paused_ = !is_paused_;
|
| + if (IsInProgress()) {
|
| + if (is_paused_)
|
| + request_handle_->ResumeRequest();
|
| + else
|
| + request_handle_->PauseRequest();
|
| + is_paused_ = !is_paused_;
|
| + } else if (IsInterrupted()) {
|
| + auto_resume_count_ = 0; // User input resets the counter.
|
| + ResumeInterruptedDownload();
|
| + }
|
| +
|
| UpdateObservers();
|
| }
|
|
|
| void DownloadItemImpl::Cancel(bool user_cancel) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| - last_reason_ = user_cancel ?
|
| - DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
|
| - DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
|
| -
|
| VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
|
| - if (state_ != IN_PROGRESS_INTERNAL) {
|
| + if (state_ != IN_PROGRESS_INTERNAL && state_ != INTERRUPTED_INTERNAL) {
|
| // Small downloads might be complete before this method has
|
| // a chance to run.
|
| return;
|
| }
|
|
|
| + last_reason_ = user_cancel ?
|
| + DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
|
| + DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
|
| +
|
| RecordDownloadCount(CANCELLED_COUNT);
|
|
|
| TransitionTo(CANCELLED_INTERNAL);
|
| @@ -364,6 +385,7 @@ void DownloadItemImpl::Cancel(bool user_cancel) {
|
| }
|
|
|
| void DownloadItemImpl::Delete(DeleteReason reason) {
|
| + VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| switch (reason) {
|
| @@ -392,6 +414,7 @@ void DownloadItemImpl::Delete(DeleteReason reason) {
|
| }
|
|
|
| void DownloadItemImpl::Remove() {
|
| + VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| delegate_->AssertStateConsistent(this);
|
| @@ -461,14 +484,98 @@ bool DownloadItemImpl::IsPaused() const {
|
| return is_paused_;
|
| }
|
|
|
| +bool DownloadItemImpl::IsResuming() const {
|
| + return is_resuming_;
|
| +}
|
| +
|
| +bool DownloadItemImpl::CanResumeInterrupted() const {
|
| + return GetResumeMode() != RESUME_MODE_INVALID;
|
| +}
|
| +
|
| +DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + if (!IsInterrupted())
|
| + return RESUME_MODE_INVALID;
|
| +
|
| + ResumeMode mode = RESUME_MODE_INVALID;
|
| +
|
| + switch(last_reason_) {
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
|
| + case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
|
| + mode = RESUME_MODE_IMMEDIATE_CONTINUE; // Continue immediately.
|
| + break;
|
| +
|
| + case DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
|
| + case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
|
| + mode = RESUME_MODE_IMMEDIATE_RESTART; // Restart immediately.
|
| + break;
|
| +
|
| + case DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
|
| + case DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
|
| + case DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
|
| + case DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
|
| + case DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
|
| + case DOWNLOAD_INTERRUPT_REASON_CRASH:
|
| + mode = RESUME_MODE_USER_CONTINUE; // Continue via user input.
|
| + break;
|
| +
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
|
| + mode = RESUME_MODE_USER_RESTART; // Restart via user input.
|
| + break;
|
| +
|
| + case DOWNLOAD_INTERRUPT_REASON_NONE:
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
|
| + case DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
|
| + case DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
|
| + break;
|
| +
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
|
| + case DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
|
| + break;
|
| + }
|
| +
|
| + // Check if we have exhausted the number of automatic retry attempts.
|
| + if (auto_resume_count_ >= kMaxAutoResumeAttempts) {
|
| + if (mode == RESUME_MODE_IMMEDIATE_CONTINUE)
|
| + mode = RESUME_MODE_USER_CONTINUE;
|
| + else if (mode == RESUME_MODE_IMMEDIATE_RESTART)
|
| + mode = RESUME_MODE_USER_RESTART;
|
| + }
|
| +
|
| + return mode;
|
| +}
|
| +
|
| +void DownloadItemImpl::AutoResumeIfValid() {
|
| + DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + ResumeMode mode = GetResumeMode();
|
| +
|
| + if ((mode == RESUME_MODE_IMMEDIATE_RESTART) ||
|
| + (mode == RESUME_MODE_IMMEDIATE_CONTINUE)) {
|
| + if (mode == RESUME_MODE_IMMEDIATE_RESTART) {
|
| + received_bytes_ = 0; // Restart instead of continuing.
|
| + hash_state_ = "";
|
| + last_modified_time_ = "";
|
| + etag_ = "";
|
| + }
|
| +
|
| + auto_resume_count_++;
|
| +
|
| + ResumeInterruptedDownload();
|
| + }
|
| +}
|
| +
|
| bool DownloadItemImpl::IsTemporary() const {
|
| return is_temporary_;
|
| }
|
|
|
| -// TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to
|
| -// |IsPartialDownload()|, when resuming interrupted downloads is implemented.
|
| bool DownloadItemImpl::IsPartialDownload() const {
|
| - return InternalToExternalState(state_) == IN_PROGRESS;
|
| + DownloadState state = InternalToExternalState(state_);
|
| + return (state == IN_PROGRESS) || (state == INTERRUPTED);
|
| }
|
|
|
| bool DownloadItemImpl::IsInProgress() const {
|
| @@ -476,8 +583,7 @@ bool DownloadItemImpl::IsInProgress() const {
|
| }
|
|
|
| bool DownloadItemImpl::IsCancelled() const {
|
| - DownloadState external_state = InternalToExternalState(state_);
|
| - return external_state == CANCELLED || external_state == INTERRUPTED;
|
| + return InternalToExternalState(state_) == CANCELLED;
|
| }
|
|
|
| bool DownloadItemImpl::IsInterrupted() const {
|
| @@ -665,6 +771,22 @@ bool DownloadItemImpl::CanOpenDownload() {
|
| return !file_externally_removed_;
|
| }
|
|
|
| +bool DownloadItemImpl::CanResumeDownload() const {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + // Do not allow interrupted downloads to be resumed until the target name
|
| + // has been determined, and the user has validated any dangerous items.
|
| + // TODO(rdsmith) -- Add a state indicating that filename determination has
|
| + // occurred.
|
| + if (GetTargetFilePath().empty())
|
| + return false;
|
| +
|
| + if (GetSafetyState() == DANGEROUS)
|
| + return false;
|
| +
|
| + return IsInProgress() || CanResumeInterrupted();
|
| +}
|
| +
|
| bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
|
| return delegate_->ShouldOpenFileBasedOnExtension(GetUserVerifiedFilePath());
|
| }
|
| @@ -747,24 +869,32 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
|
| " received = %" PRId64
|
| " reason = %s"
|
| " paused = %c"
|
| + " resuming = %c"
|
| + " resume_mode = %s"
|
| + " auto_resume_count = %d"
|
| " safety = %s"
|
| + " all_data_saved = %c"
|
| " last_modified = '%s'"
|
| " etag = '%s'"
|
| + " has_download_file = %s"
|
| " url_chain = \n\t\"%s\"\n\t"
|
| - " full_path = \"%" PRFilePath "\""
|
| - " target_path = \"%" PRFilePath "\""
|
| - " has download file = %s",
|
| + " full_path = \"%" PRFilePath "\"\n\t"
|
| + " target_path = \"%" PRFilePath "\"",
|
| GetTotalBytes(),
|
| GetReceivedBytes(),
|
| InterruptReasonDebugString(last_reason_).c_str(),
|
| IsPaused() ? 'T' : 'F',
|
| + IsResuming() ? 'T' : 'F',
|
| + DebugResumeModeString(GetResumeMode()),
|
| + auto_resume_count_,
|
| DebugSafetyStateString(GetSafetyState()),
|
| + AllDataSaved() ? 'T' : 'F',
|
| GetLastModifiedTime().c_str(),
|
| GetETag().c_str(),
|
| + download_file_.get() ? "true" : "false",
|
| url_list.c_str(),
|
| GetFullPath().value().c_str(),
|
| - GetTargetFilePath().value().c_str(),
|
| - download_file_.get() ? "true" : "false");
|
| + GetTargetFilePath().value().c_str());
|
| } else {
|
| description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
|
| }
|
| @@ -788,11 +918,6 @@ void DownloadItemImpl::OnDownloadedFileRemoved() {
|
| UpdateObservers();
|
| }
|
|
|
| -base::WeakPtr<DownloadDestinationObserver>
|
| -DownloadItemImpl::DestinationObserverAsWeakPtr() {
|
| - return weak_ptr_factory_.GetWeakPtr();
|
| -}
|
| -
|
| void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
|
| total_bytes_ = total_bytes;
|
| }
|
| @@ -949,10 +1074,26 @@ void DownloadItemImpl::Init(bool active,
|
| }
|
|
|
| // We're starting the download.
|
| -void DownloadItemImpl::Start(scoped_ptr<DownloadFile> file) {
|
| +void DownloadItemImpl::Start(
|
| + scoped_ptr<DownloadFile> file,
|
| + scoped_ptr<DownloadRequestHandleInterface> req_handle) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| DCHECK(!download_file_.get());
|
| DCHECK(file.get());
|
| + DCHECK(req_handle.get());
|
| +
|
| download_file_ = file.Pass();
|
| + request_handle_ = req_handle.Pass();
|
| +
|
| + is_resuming_ = (state_ == INTERRUPTED_INTERNAL);
|
| +
|
| + TransitionTo(IN_PROGRESS_INTERNAL);
|
| +
|
| + last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
|
| +
|
| + if (is_resuming_) {
|
| + FOR_EACH_OBSERVER(Observer, observers_, OnDownloadResumed(this));
|
| + }
|
|
|
| BrowserThread::PostTask(
|
| BrowserThread::FILE, FROM_HERE,
|
| @@ -965,6 +1106,7 @@ void DownloadItemImpl::Start(scoped_ptr<DownloadFile> file) {
|
|
|
| void DownloadItemImpl::OnDownloadFileInitialized(
|
| DownloadInterruptReason result) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
|
| Interrupt(result);
|
| // TODO(rdsmith): It makes no sense to continue along the
|
| @@ -972,7 +1114,7 @@ void DownloadItemImpl::OnDownloadFileInitialized(
|
| // the way the code has historically worked, and this allows us
|
| // to get the download persisted and observers of the download manager
|
| // notified, so tests work. When we execute all side effects of cancel
|
| - // (including queue removal) immedately rather than waiting for
|
| + // (including queue removal) immediately rather than waiting for
|
| // persistence we should replace this comment with a "return;".
|
| }
|
|
|
| @@ -1097,11 +1239,12 @@ void DownloadItemImpl::OnDownloadCompleting() {
|
| }
|
|
|
| void DownloadItemImpl::ReadyForDownloadCompletionDone() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| if (state_ != IN_PROGRESS_INTERNAL)
|
| return;
|
|
|
| - VLOG(20) << __FUNCTION__ << "()"
|
| - << " " << DebugString(true);
|
| + VLOG(20) << __FUNCTION__ << "()" << " " << DebugString(true);
|
| DCHECK(!GetTargetFilePath().empty());
|
| DCHECK_NE(DANGEROUS, GetSafetyState());
|
|
|
| @@ -1180,6 +1323,8 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
|
| }
|
|
|
| void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| auto_opened_ = auto_opened;
|
| Completed();
|
| }
|
| @@ -1213,8 +1358,41 @@ void DownloadItemImpl::Completed() {
|
|
|
| // **** End of Download progression cascade
|
|
|
| +void DownloadItemImpl::ResumeInterruptedDownload() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + // Handle the case of clicking 'Resume' in the download shelf.
|
| + DCHECK(IsInterrupted());
|
| +
|
| + DVLOG(20) << __FUNCTION__ << "()" << DebugString(true);
|
| +
|
| + // Restart the download.
|
| + if (!GetWebContents()) {
|
| + Interrupt(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
|
| + return;
|
| + }
|
| +
|
| + scoped_ptr<DownloadUrlParameters> download_params(
|
| + DownloadUrlParameters::FromWebContents(GetWebContents(),
|
| + GetOriginalUrl()));
|
| +
|
| + download_params->set_file_path(GetFullPath());
|
| + download_params->set_offset(GetReceivedBytes());
|
| + download_params->set_hash_state(GetHashState());
|
| +
|
| + Referrer referrer(GetReferrerUrl(), WebKit::WebReferrerPolicyDefault);
|
| + download_params->set_referrer(referrer);
|
| + download_params->set_last_modified(GetLastModifiedTime());
|
| + download_params->set_etag(GetETag());
|
| + download_params->set_callback(DownloadUrlParameters::OnStartedCallback());
|
| +
|
| + delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId());
|
| +}
|
| +
|
| // An error occurred somewhere.
|
| void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| // Somewhat counter-intuitively, it is possible for us to receive an
|
| // interrupt after we've already been interrupted. The generation of
|
| // interrupts from the file thread Renames and the generation of
|
| @@ -1229,6 +1407,8 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
|
| return;
|
|
|
| last_reason_ = reason;
|
| + is_resuming_ = false;
|
| +
|
| TransitionTo(INTERRUPTED_INTERNAL);
|
|
|
| CancelDownloadFile();
|
| @@ -1236,15 +1416,26 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
|
| // Cancel the originating URL request.
|
| request_handle_->CancelRequest();
|
|
|
| + FOR_EACH_OBSERVER(Observer, observers_, OnDownloadInterrupted(this));
|
| +
|
| RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
|
| delegate_->DownloadStopped(this);
|
| +
|
| + AutoResumeIfValid();
|
| +}
|
| +
|
| +base::WeakPtr<DownloadDestinationObserver>
|
| +DownloadItemImpl::DestinationObserverAsWeakPtr() {
|
| + return weak_ptr_factory_.GetWeakPtr();
|
| }
|
|
|
| void DownloadItemImpl::CancelDownloadFile() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| // TODO(rdsmith/benjhayden): Remove condition as part of
|
| - // SavePackage integration.
|
| - // download_file_ can be NULL if Interrupt() is called after the download file
|
| - // has been released.
|
| + // |SavePackage| integration.
|
| + // |download_file_| can be NULL if Interrupt() is called after the
|
| + // download file has been released.
|
| if (!is_save_package_download_ && download_file_.get()) {
|
| BrowserThread::PostTask(
|
| BrowserThread::FILE, FROM_HERE,
|
| @@ -1259,6 +1450,8 @@ bool DownloadItemImpl::IsDownloadReadyForCompletion() {
|
| << " " << (state_ == IN_PROGRESS_INTERNAL)
|
| << " " << !GetTargetFilePath().empty()
|
| << " " << (target_path_.DirName() == current_path_.DirName());
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| // If we don't have all the data, the download is not ready for
|
| // completion.
|
| if (!AllDataSaved())
|
| @@ -1288,6 +1481,8 @@ bool DownloadItemImpl::IsDownloadReadyForCompletion() {
|
| }
|
|
|
| void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| if (state_ == new_state)
|
| return;
|
|
|
| @@ -1311,6 +1506,14 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
|
| base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
|
| received_bytes_, &hash_state_));
|
| break;
|
| + case IN_PROGRESS_INTERNAL:
|
| + if (is_resuming_) {
|
| + bound_net_log_.AddEvent(
|
| + net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
|
| + base::Bind(&ItemResumingNetLogCallback,
|
| + false, last_reason_, received_bytes_, &hash_state_));
|
| + }
|
| + break;
|
| case CANCELLED_INTERNAL:
|
| bound_net_log_.AddEvent(
|
| net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
|
| @@ -1326,13 +1529,14 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
|
| << " " << InternalToExternalState(state_);
|
|
|
| // Only update observers on user visible state changes.
|
| - if (InternalToExternalState(old_state) != InternalToExternalState(state_))
|
| + DownloadState external_state = InternalToExternalState(state_);
|
| + DownloadState old_external_state = InternalToExternalState(old_state);
|
| +
|
| + if (old_external_state != external_state)
|
| UpdateObservers();
|
|
|
| - bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
|
| - state_ != COMPLETING_INTERNAL);
|
| - bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
|
| - old_state != COMPLETING_INTERNAL);
|
| + bool is_done = external_state != IN_PROGRESS;
|
| + bool was_done = old_external_state != IN_PROGRESS;
|
| if (is_done && !was_done)
|
| bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
|
| }
|
| @@ -1405,6 +1609,10 @@ DownloadItemImpl::ExternalToInternalState(
|
| return MAX_DOWNLOAD_INTERNAL_STATE;
|
| }
|
|
|
| +const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
|
| + return bound_net_log_;
|
| +}
|
| +
|
| const char* DownloadItemImpl::DebugDownloadStateString(
|
| DownloadInternalState state) {
|
| switch (state) {
|
| @@ -1424,4 +1632,22 @@ const char* DownloadItemImpl::DebugDownloadStateString(
|
| };
|
| }
|
|
|
| +const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
|
| + switch (mode) {
|
| + case RESUME_MODE_INVALID:
|
| + return "INVALID";
|
| + case RESUME_MODE_IMMEDIATE_CONTINUE:
|
| + return "IMMEDIATE_CONTINUE";
|
| + case RESUME_MODE_IMMEDIATE_RESTART:
|
| + return "IMMEDIATE_RESTART";
|
| + case RESUME_MODE_USER_CONTINUE:
|
| + return "USER_CONTINUE";
|
| + case RESUME_MODE_USER_RESTART:
|
| + return "USER_RESTART";
|
| + default:
|
| + NOTREACHED() << "Unknown resume mode " << mode;
|
| + return "unknown";
|
| + }
|
| +}
|
| +
|
| } // namespace content
|
|
|