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

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

Issue 10831302: Download resumption - Preliminary (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fixed signed/unsigned compare issue. Created 8 years, 1 month 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 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
« no previous file with comments | « content/browser/download/download_item_impl.h ('k') | content/browser/download/download_item_impl_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698