| 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 1413393f00e01351ebee8ef8cc88407357e63261..9df61576b2f3445626ec72cfd2d4a3df7d121f9b 100644
|
| --- a/content/browser/download/download_item_impl.cc
|
| +++ b/content/browser/download/download_item_impl.cc
|
| @@ -309,33 +309,39 @@ void DownloadItemImpl::Pause() {
|
|
|
| void DownloadItemImpl::Resume() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + switch (state_) {
|
| + case IN_PROGRESS_INTERNAL:
|
| + if (!is_paused_)
|
| + return;
|
| + request_handle_->ResumeRequest();
|
| + is_paused_ = false;
|
| + UpdateObservers();
|
| + return;
|
|
|
| - // Ignore irrelevant states.
|
| - if (state_ == COMPLETE_INTERNAL ||
|
| - state_ == COMPLETING_INTERNAL ||
|
| - state_ == CANCELLED_INTERNAL ||
|
| - (state_ == IN_PROGRESS_INTERNAL && !is_paused_))
|
| - return;
|
| + case COMPLETING_INTERNAL:
|
| + case COMPLETE_INTERNAL:
|
| + case CANCELLED_INTERNAL:
|
| + case RESUMING_INTERNAL:
|
| + return;
|
|
|
| - if (state_ == INTERRUPTED_INTERNAL) {
|
| - auto_resume_count_ = 0; // User input resets the counter.
|
| - ResumeInterruptedDownload();
|
| - return;
|
| - }
|
| - DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
|
| + case INTERRUPTED_INTERNAL:
|
| + auto_resume_count_ = 0; // User input resets the counter.
|
| + ResumeInterruptedDownload();
|
| + return;
|
|
|
| - request_handle_->ResumeRequest();
|
| - is_paused_ = false;
|
| - UpdateObservers();
|
| + case MAX_DOWNLOAD_INTERNAL_STATE:
|
| + NOTREACHED();
|
| + }
|
| }
|
|
|
| void DownloadItemImpl::Cancel(bool user_cancel) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
|
| - if (state_ != IN_PROGRESS_INTERNAL && state_ != INTERRUPTED_INTERNAL) {
|
| - // Small downloads might be complete before this method has
|
| - // a chance to run.
|
| + if (state_ != IN_PROGRESS_INTERNAL &&
|
| + state_ != INTERRUPTED_INTERNAL &&
|
| + state_ != RESUMING_INTERNAL) {
|
| + // Small downloads might be complete before this method has a chance to run.
|
| return;
|
| }
|
|
|
| @@ -352,7 +358,7 @@ void DownloadItemImpl::Cancel(bool user_cancel) {
|
| if (!is_save_package_download_ && download_file_)
|
| ReleaseDownloadFile(true);
|
|
|
| - if (state_ != INTERRUPTED_INTERNAL) {
|
| + if (state_ == IN_PROGRESS_INTERNAL) {
|
| // Cancel the originating URL request unless it's already been cancelled
|
| // by interrupt.
|
| request_handle_->CancelRequest();
|
| @@ -1048,6 +1054,14 @@ void DownloadItemImpl::Start(
|
| download_file_ = file.Pass();
|
| request_handle_ = req_handle.Pass();
|
|
|
| + if (IsCancelled()) {
|
| + // The download was in the process of resuming when it was cancelled. Don't
|
| + // proceed.
|
| + ReleaseDownloadFile(true);
|
| + request_handle_->CancelRequest();
|
| + return;
|
| + }
|
| +
|
| TransitionTo(IN_PROGRESS_INTERNAL);
|
|
|
| last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
|
| @@ -1326,6 +1340,25 @@ void DownloadItemImpl::Completed() {
|
| }
|
| }
|
|
|
| +void DownloadItemImpl::OnResumeRequestStarted(DownloadItem* item,
|
| + net::Error error) {
|
| + // If |item| is not NULL, then Start() has been called already, and nothing
|
| + // more needs to be done here.
|
| + if (item) {
|
| + DCHECK_EQ(net::OK, error);
|
| + DCHECK_EQ(static_cast<DownloadItem*>(this), item);
|
| + return;
|
| + }
|
| + // Otherwise, the request failed without passing through
|
| + // DownloadResourceHandler::OnResponseStarted.
|
| + if (error == net::OK)
|
| + error = net::ERR_FAILED;
|
| + DownloadInterruptReason reason =
|
| + ConvertNetErrorToInterruptReason(error, DOWNLOAD_INTERRUPT_FROM_NETWORK);
|
| + DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
|
| + Interrupt(reason);
|
| +}
|
| +
|
| // **** End of Download progression cascade
|
|
|
| // An error occurred somewhere.
|
| @@ -1342,7 +1375,7 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
|
| // interrupts to race with cancels.
|
|
|
| // Whatever happens, the first one to hit the UI thread wins.
|
| - if (state_ != IN_PROGRESS_INTERNAL)
|
| + if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL)
|
| return;
|
|
|
| last_reason_ = reason;
|
| @@ -1555,7 +1588,7 @@ void DownloadItemImpl::ResumeInterruptedDownload() {
|
| return;
|
|
|
| // If we're not interrupted, ignore the request; our caller is drunk.
|
| - if (!IsInterrupted())
|
| + if (state_ != INTERRUPTED_INTERNAL)
|
| return;
|
|
|
| // If we can't get a web contents, we can't resume the download.
|
| @@ -1584,11 +1617,15 @@ void DownloadItemImpl::ResumeInterruptedDownload() {
|
| download_params->set_hash_state(GetHashState());
|
| download_params->set_last_modified(GetLastModifiedTime());
|
| download_params->set_etag(GetETag());
|
| + download_params->set_callback(
|
| + base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
|
|
| delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId());
|
| -
|
| // Just in case we were interrupted while paused.
|
| is_paused_ = false;
|
| +
|
| + TransitionTo(RESUMING_INTERNAL);
|
| }
|
|
|
| // static
|
| @@ -1605,30 +1642,33 @@ DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
|
| return CANCELLED;
|
| case INTERRUPTED_INTERNAL:
|
| return INTERRUPTED;
|
| - default:
|
| - NOTREACHED();
|
| + case RESUMING_INTERNAL:
|
| + return INTERRUPTED;
|
| + case MAX_DOWNLOAD_INTERNAL_STATE:
|
| + break;
|
| }
|
| + NOTREACHED();
|
| return MAX_DOWNLOAD_STATE;
|
| }
|
|
|
| // static
|
| DownloadItemImpl::DownloadInternalState
|
| DownloadItemImpl::ExternalToInternalState(
|
| - DownloadState external_state) {
|
| - switch (external_state) {
|
| - case IN_PROGRESS:
|
| - return IN_PROGRESS_INTERNAL;
|
| - case COMPLETE:
|
| - return COMPLETE_INTERNAL;
|
| - case CANCELLED:
|
| - return CANCELLED_INTERNAL;
|
| - case INTERRUPTED:
|
| - return INTERRUPTED_INTERNAL;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - return MAX_DOWNLOAD_INTERNAL_STATE;
|
| - }
|
| + DownloadState external_state) {
|
| + switch (external_state) {
|
| + case IN_PROGRESS:
|
| + return IN_PROGRESS_INTERNAL;
|
| + case COMPLETE:
|
| + return COMPLETE_INTERNAL;
|
| + case CANCELLED:
|
| + return CANCELLED_INTERNAL;
|
| + case INTERRUPTED:
|
| + return INTERRUPTED_INTERNAL;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| + return MAX_DOWNLOAD_INTERNAL_STATE;
|
| +}
|
|
|
| const char* DownloadItemImpl::DebugDownloadStateString(
|
| DownloadInternalState state) {
|
| @@ -1643,10 +1683,13 @@ const char* DownloadItemImpl::DebugDownloadStateString(
|
| return "CANCELLED";
|
| case INTERRUPTED_INTERNAL:
|
| return "INTERRUPTED";
|
| - default:
|
| - NOTREACHED() << "Unknown download state " << state;
|
| - return "unknown";
|
| + case RESUMING_INTERNAL:
|
| + return "RESUMING";
|
| + case MAX_DOWNLOAD_INTERNAL_STATE:
|
| + break;
|
| };
|
| + NOTREACHED() << "Unknown download state " << state;
|
| + return "unknown";
|
| }
|
|
|
| const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
|
|
|