Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1052)

Unified Diff: content/browser/download/download_item_impl.cc

Issue 11571025: Initial CL for Downloads resumption. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Incorporated comments. Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 042934d69b2773850c9b81a3c04a1792c56cc669..b673ac61612d05968513a14a4f8ace156a00feff 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -27,6 +27,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/format_macros.h"
#include "base/logging.h"
@@ -40,15 +41,22 @@
#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/content_switches.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.
@@ -111,6 +119,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,
@@ -144,6 +155,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
end_time_(end_time),
delegate_(delegate),
is_paused_(false),
+ auto_resume_count_(0),
open_when_complete_(false),
file_externally_removed_(false),
safety_state_(SAFE),
@@ -167,10 +179,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) ?
@@ -195,6 +205,7 @@ DownloadItemImpl::DownloadItemImpl(
start_time_(info.start_time),
delegate_(delegate),
is_paused_(false),
+ auto_resume_count_(0),
open_when_complete_(false),
file_externally_removed_(false),
safety_state_(SAFE),
@@ -207,7 +218,7 @@ DownloadItemImpl::DownloadItemImpl(
bound_net_log_(bound_net_log),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
delegate_->Attach();
- Init(true /* actively downloading */, SRC_NEW_DOWNLOAD);
+ Init(true /* actively downloading */, SRC_ACTIVE_DOWNLOAD);
// Link the event sources.
bound_net_log_.AddEvent(
@@ -248,6 +259,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
start_time_(base::Time::Now()),
delegate_(delegate),
is_paused_(false),
+ auto_resume_count_(0),
open_when_complete_(false),
file_externally_removed_(false),
safety_state_(SAFE),
@@ -321,35 +333,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)
+ // Ignore pause/resumes when we've passed the commit point.
+ if (state_ == COMPLETING_INTERNAL || state_ == COMPLETE_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);
@@ -361,6 +379,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) {
@@ -389,6 +408,7 @@ void DownloadItemImpl::Delete(DeleteReason reason) {
}
void DownloadItemImpl::Remove() {
+ VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
delegate_->AssertStateConsistent(this);
@@ -462,10 +482,9 @@ 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 {
@@ -473,8 +492,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 {
@@ -750,24 +768,30 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
" received = %" PRId64
" reason = %s"
" paused = %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',
+ 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());
}
@@ -781,6 +805,127 @@ void DownloadItemImpl::MockDownloadOpenForTesting() {
open_enabled_ = false;
}
+DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!IsInterrupted())
+ return RESUME_MODE_INVALID;
+
+ // We can't continue without a handle on the intermediate file.
+ const bool force_restart = current_path_.empty();
+
+ // We won't auto-restart if we've used up our attempts or the
+ // download has been paused by user action.
+ const bool force_user =
+ (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_);
+
+ ResumeMode mode = RESUME_MODE_INVALID;
+
+ switch(last_reason_) {
+ case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
+ case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
+ if (force_restart && force_user)
+ mode = RESUME_MODE_USER_RESTART;
+ else if (force_restart)
+ mode = RESUME_MODE_IMMEDIATE_RESTART;
+ else if (force_user)
+ mode = RESUME_MODE_USER_CONTINUE;
+ else
+ mode = RESUME_MODE_IMMEDIATE_CONTINUE;
+ break;
+
+ case DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
+ case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
+ case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
+ if (force_user)
+ mode = RESUME_MODE_USER_RESTART;
+ else
+ mode = RESUME_MODE_IMMEDIATE_RESTART;
+ 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:
+ if (force_restart)
+ mode = RESUME_MODE_USER_RESTART;
+ else
+ mode = RESUME_MODE_USER_CONTINUE;
+ 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;
+ 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:
+ case DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
+ case DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
+ mode = RESUME_MODE_INVALID;
+ break;
+ }
+
+ return mode;
+}
+
+void DownloadItemImpl::ResumeInterruptedDownload() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // If the flag for downloads resumption isn't enabled, ignore
+ // this request.
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (!command_line.HasSwitch(switches::kEnableDownloadResumption))
+ return;
+
+ // Handle the case of clicking 'Resume' in the download shelf.
+ DCHECK(IsInterrupted());
+
+ DVLOG(20) << __FUNCTION__ << "()" << DebugString(true);
+
+ // If we can't get a web contents, we can't resume the download.
+ // TODO(rdsmith): Find some alternative web contents to use--this
+ // means we can't restart a download if it's a download imported
+ // from the history.
+ if (!GetWebContents())
+ return;
+
+ // Reset the appropriate state if restarting.
+ ResumeMode mode = GetResumeMode();
+ if (mode == RESUME_MODE_IMMEDIATE_RESTART ||
+ mode == RESUME_MODE_USER_RESTART) {
+ received_bytes_ = 0;
+ hash_state_ = "";
+ last_modified_time_ = "";
+ etag_ = "";
+ }
+
+ 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());
benjhayden 2013/01/08 16:41:17 This looks unnecessary.
Randy Smith (Not in Mondays) 2013/01/09 22:34:37 Done.
+
+ delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId());
+
+ // Just in case we were interrupted while paused.
+ is_paused_ = false;
+}
+
void DownloadItemImpl::NotifyRemoved() {
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
}
@@ -796,6 +941,10 @@ DownloadItemImpl::DestinationObserverAsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
+const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
+ return bound_net_log_;
+}
+
void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
total_bytes_ = total_bytes;
}
@@ -952,10 +1101,20 @@ 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();
+
+ TransitionTo(IN_PROGRESS_INTERNAL);
+
+ last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
@@ -968,6 +1127,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
@@ -975,10 +1135,23 @@ 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;".
}
+ // If we're resuming an interrupted download, we may already know
+ // the download target so we can skip target name determination.
+ if (!GetTargetFilePath().empty() && !GetFullPath().empty()) {
+ delegate_->ShowDownloadInBrowser(this);
+ MaybeCompleteDownload();
+ return;
+ }
+
+ // The target path might be set and the full path empty if we failed
+ // the intermediate rename--re-do file name determination in this case.
+ // TODO(rdsmith,asanka): Clean up this logic.
+ target_path_ = FilePath();
+
delegate_->DetermineDownloadTarget(
this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
weak_ptr_factory_.GetWeakPtr()));
@@ -1000,6 +1173,14 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
return;
}
+ // TODO(rdsmith,asanka): We are ignoring the possibility that the download
+ // has been interrupted at this point until we finish the intermediate
+ // rename and set the full path. That's dangerous, because we might race
+ // with resumption, either manual (because the interrupt is visible to the
+ // UI) or automatic. If we keep the "ignore an error on download until file
+ // name determination complete" semantics, we need to make sure that the
+ // error is kept completely invisible until that point.
+
VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
<< " " << danger_type << " " << DebugString(true);
@@ -1013,16 +1194,6 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
// space/permission/availability constraints.
DCHECK(intermediate_path.DirName() == target_path.DirName());
- if (state_ != IN_PROGRESS_INTERNAL) {
benjhayden 2013/01/08 16:41:17 Why was this removed?
Randy Smith (Not in Mondays) 2013/01/09 22:34:37 So as you're probably aware, the interaction betwe
- // If we've been cancelled or interrupted while the target was being
- // determined, continue the cascade with a null name.
- // The error doesn't matter as the cause of download stoppage
- // will already have been recorded and will be retained, but we use
- // whatever was recorded for consistency.
- OnDownloadRenamedToIntermediateName(last_reason_, FilePath());
- return;
- }
-
// Rename to intermediate name.
// TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
// spurious rename when we can just rename to the final
@@ -1174,6 +1345,8 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
}
void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
auto_opened_ = auto_opened;
Completed();
}
@@ -1208,6 +1381,8 @@ void DownloadItemImpl::Completed() {
// 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
@@ -1222,21 +1397,36 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
return;
last_reason_ = reason;
+
TransitionTo(INTERRUPTED_INTERNAL);
- CancelDownloadFile();
+ ResumeMode resume_mode = GetResumeMode();
+ if (resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
+ resume_mode == RESUME_MODE_USER_RESTART) {
+ // Remove the download file; no point in leaving data around we
+ // aren't going to use.
+ CancelDownloadFile();
+ } else {
+ // Keep the file around and maybe re-use it.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&DownloadFileDetach, base::Passed(&download_file_)));
+ }
// Cancel the originating URL request.
request_handle_->CancelRequest();
RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
+ AutoResumeIfValid();
}
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,
@@ -1281,6 +1471,8 @@ bool DownloadItemImpl::IsDownloadReadyForCompletion(
}
void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
if (state_ == new_state)
return;
@@ -1304,6 +1496,14 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
received_bytes_, &hash_state_));
break;
+ case IN_PROGRESS_INTERNAL:
+ if (old_state == INTERRUPTED_INTERNAL) {
+ 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,
@@ -1319,15 +1519,25 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
<< " " << InternalToExternalState(state_);
// Only update observers on user visible state changes.
- if (InternalToExternalState(old_state) != InternalToExternalState(state_))
+ if (InternalToExternalState(state_) != InternalToExternalState(old_state))
UpdateObservers();
bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
state_ != COMPLETING_INTERNAL);
bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
old_state != COMPLETING_INTERNAL);
+ // Termination
if (is_done && !was_done)
bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
+
+ // Resumption
+ if (was_done && !is_done) {
+ std::string file_name(target_path_.BaseName().AsUTF8Unsafe());
+ bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
+ base::Bind(&ItemActivatedNetLogCallback,
+ this, SRC_ACTIVE_DOWNLOAD,
+ &file_name));
+ }
}
void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
@@ -1360,6 +1570,21 @@ void DownloadItemImpl::SetFullPath(const FilePath& new_path) {
UpdateObservers();
}
+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) {
+ return;
+ }
+
+ auto_resume_count_++;
+
+ ResumeInterruptedDownload();
+}
+
// static
DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
DownloadInternalState internal_state) {
@@ -1418,4 +1643,21 @@ 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";
+ }
+ NOTREACHED() << "Unknown resume mode " << mode;
+ return "unknown";
+}
+
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698