Chromium Code Reviews| 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 028e6d5531ca7d85481b992b5e5990dadedc3f50..f5564e647991634454cb96b6f98fe51b6ade7345 100644 |
| --- a/content/browser/download/download_item_impl.cc |
| +++ b/content/browser/download/download_item_impl.cc |
| @@ -192,7 +192,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, |
| bytes_per_sec_(0), |
| last_modified_time_(info.last_modified), |
| etag_(info.etag), |
| - last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE), |
| + last_reason_(info.result), |
| start_tick_(base::TimeTicks::Now()), |
| state_(INITIAL_INTERNAL), |
| danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), |
| @@ -205,7 +205,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, |
| auto_opened_(false), |
| is_temporary_(!info.save_info->file_path.empty()), |
| all_data_saved_(false), |
| - destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE), |
| + destination_error_(DOWNLOAD_INTERRUPT_REASON_NONE), |
| opened_(false), |
| delegate_delayed_complete_(false), |
| bound_net_log_(bound_net_log), |
| @@ -295,6 +295,7 @@ void DownloadItemImpl::RemoveObserver(Observer* observer) { |
| void DownloadItemImpl::UpdateObservers() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + DVLOG(20) << __FUNCTION__ << "()"; |
| FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this)); |
| } |
| @@ -318,7 +319,9 @@ void DownloadItemImpl::ValidateDangerousDownload() { |
| net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, |
| base::Bind(&ItemCheckedNetLogCallback, GetDangerType())); |
| - UpdateObservers(); |
| + UpdateObservers(); // TODO(asanka): This is potentially unsafe. The download |
| + // may not be in a consistent state or around at all after |
| + // invoking observers. |
|
Randy Smith (Not in Mondays)
2016/02/12 19:10:28
I presume there are no observers that do anything
asanka
2016/02/12 20:52:28
Yeah. None of the observers do anything crazy, but
|
| MaybeCompleteDownload(); |
| } |
| @@ -361,6 +364,7 @@ void DownloadItemImpl::Pause() { |
| return; |
| case TARGET_PENDING_INTERNAL: |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
|
Randy Smith (Not in Mondays)
2016/02/12 21:57:19
Hasn't the request already failed, or doesn't exis
asanka
2016/02/12 23:34:47
True. Moved to the no-op block above.
|
| case IN_PROGRESS_INTERNAL: |
| request_handle_->PauseRequest(); |
| is_paused_ = true; |
| @@ -375,18 +379,17 @@ void DownloadItemImpl::Pause() { |
| void DownloadItemImpl::Resume() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
| switch (state_) { |
| case INITIAL_INTERNAL: |
| case COMPLETING_INTERNAL: |
| case COMPLETE_INTERNAL: |
| - case CANCELLED_INTERNAL: |
| - // Nothing to resume. |
| - case RESUMING_INTERNAL: |
| - // Resumption in progress. |
| - DCHECK(!is_paused_); |
| + case CANCELLED_INTERNAL: // Nothing to resume. |
| + case RESUMING_INTERNAL: // Resumption in progress. |
| return; |
| case TARGET_PENDING_INTERNAL: |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
|
Randy Smith (Not in Mondays)
2016/02/12 21:57:19
Same as above.
asanka
2016/02/12 23:34:47
Same.
|
| case IN_PROGRESS_INTERNAL: |
| if (!is_paused_) |
| return; |
| @@ -398,6 +401,7 @@ void DownloadItemImpl::Resume() { |
| case INTERRUPTED_INTERNAL: |
| auto_resume_count_ = 0; // User input resets the counter. |
| ResumeInterruptedDownload(); |
| + UpdateObservers(); |
| return; |
| case MAX_DOWNLOAD_INTERNAL_STATE: |
| @@ -411,6 +415,7 @@ void DownloadItemImpl::Cancel(bool user_cancel) { |
| DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
| Interrupt(user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED |
| : DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN); |
| + UpdateObservers(); |
| } |
| void DownloadItemImpl::Remove() { |
| @@ -419,6 +424,7 @@ void DownloadItemImpl::Remove() { |
| delegate_->AssertStateConsistent(this); |
| Interrupt(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); |
| + UpdateObservers(); |
| delegate_->AssertStateConsistent(this); |
| NotifyRemoved(); |
| @@ -485,6 +491,7 @@ bool DownloadItemImpl::CanResume() const { |
| case COMPLETE_INTERNAL: |
| case CANCELLED_INTERNAL: |
| case RESUMING_INTERNAL: |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
| return false; |
| case TARGET_PENDING_INTERNAL: |
| @@ -513,6 +520,7 @@ bool DownloadItemImpl::IsDone() const { |
| case COMPLETING_INTERNAL: |
| case RESUMING_INTERNAL: |
| case TARGET_PENDING_INTERNAL: |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
| case TARGET_RESOLVED_INTERNAL: |
| case IN_PROGRESS_INTERNAL: |
| return false; |
| @@ -937,7 +945,7 @@ DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const { |
| return mode; |
| } |
| -void DownloadItemImpl::MergeOriginInfoOnResume( |
| +void DownloadItemImpl::UpdateValidatorsOnResumption( |
| const DownloadCreateInfo& new_create_info) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| DCHECK_EQ(RESUMING_INTERNAL, state_); |
| @@ -1022,7 +1030,8 @@ void DownloadItemImpl::MarkAsComplete() { |
| DCHECK(all_data_saved_); |
| end_time_ = base::Time::Now(); |
| - TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS); |
| + TransitionTo(COMPLETE_INTERNAL); |
| + UpdateObservers(); |
| } |
| void DownloadItemImpl::DestinationUpdate(int64_t bytes_so_far, |
| @@ -1071,10 +1080,12 @@ void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) { |
| // Postpone recognition of this error until after file name determination |
| // has completed and the intermediate file has been renamed to simplify |
| // resumption conditions. |
| - if (state_ != IN_PROGRESS_INTERNAL) |
| + if (state_ == TARGET_PENDING_INTERNAL) { |
| destination_error_ = reason; |
| - else |
| - Interrupt(reason); |
| + return; |
| + } |
| + Interrupt(reason); |
| + UpdateObservers(); |
| } |
| void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { |
| @@ -1131,11 +1142,10 @@ void DownloadItemImpl::Init(bool active, |
| // We're starting the download. |
| void DownloadItemImpl::Start( |
| scoped_ptr<DownloadFile> file, |
| - scoped_ptr<DownloadRequestHandleInterface> req_handle) { |
| + scoped_ptr<DownloadRequestHandleInterface> req_handle, |
| + const DownloadCreateInfo& new_create_info) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| DCHECK(!download_file_.get()); |
| - DCHECK(file.get()); |
| - DCHECK(req_handle.get()); |
| DVLOG(20) << __FUNCTION__ << "() this=" << DebugString(true); |
| download_file_ = std::move(file); |
| @@ -1145,11 +1155,50 @@ void DownloadItemImpl::Start( |
| // The download was in the process of resuming when it was cancelled. Don't |
| // proceed. |
| ReleaseDownloadFile(true); |
| - request_handle_->CancelRequest(); |
| + if (request_handle_) |
| + request_handle_->CancelRequest(); |
| return; |
| } |
| - TransitionTo(TARGET_PENDING_INTERNAL, UPDATE_OBSERVERS); |
| + // The state could be one of the following: |
| + // |
| + // INITIAL_INTERNAL: A normal download attempt. |
| + // |
| + // RESUMING_INTERNAL: A resumption attempt. May or may not have been |
| + // successful. |
| + DCHECK(state_ == INITIAL_INTERNAL || state_ == RESUMING_INTERNAL); |
| + |
| + // If a resumption attempted failed, or if the download was DOA, then the |
| + // download should go back to being interrupted. |
| + if (new_create_info.result != DOWNLOAD_INTERRUPT_REASON_NONE) { |
| + DCHECK(!download_file_.get()); |
| + |
| + // For downloads that are interrupted on initiation, or which don't have a |
| + // target, invoke target determination so that we'll end up with a usable |
| + // filename. |
|
Randy Smith (Not in Mondays)
2016/02/12 21:57:19
nit, suggestion: I had some trouble matching this
asanka
2016/02/12 23:34:47
Ah. I simplified the condition and the comment to
|
| + if (state_ == INITIAL_INTERNAL || target_path_.empty()) { |
| + TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL); |
| + destination_error_ = new_create_info.result; |
| + DetermineDownloadTarget(); |
| + return; |
| + } |
| + |
| + // Otherwise, this was a resumption attempt which ended with an |
| + // interruption. Continue with current target path. |
| + TransitionTo(TARGET_RESOLVED_INTERNAL); |
| + Interrupt(new_create_info.result); |
| + UpdateObservers(); |
| + return; |
| + } |
| + |
| + // Successful download start. |
| + DCHECK(download_file_.get()); |
| + DCHECK(request_handle_.get()); |
| + |
| + if (state_ == RESUMING_INTERNAL) |
| + UpdateValidatorsOnResumption(new_create_info); |
| + |
| + TransitionTo(TARGET_PENDING_INTERNAL); |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, |
| @@ -1167,35 +1216,32 @@ void DownloadItemImpl::OnDownloadFileInitialized( |
| DVLOG(20) << __FUNCTION__ |
| << "() result:" << DownloadInterruptReasonToString(result); |
| if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { |
| - // Transition out to TARGET_RESOLVED_INTERNAL since this DownloadItem is |
| - // skipping the download target determination process. |
| - TransitionTo(TARGET_RESOLVED_INTERNAL, DONT_UPDATE_OBSERVERS); |
| - Interrupt(result); |
| - // TODO(rdsmith/asanka): Arguably we should show this in the UI, but |
| - // it's not at all clear what to show--we haven't done filename |
| - // determination, so we don't know what name to display. OTOH, |
| - // the failure mode of not showing the DI if the file initialization |
| - // fails isn't a good one. Can we hack up a name based on the |
| - // URLRequest? We'll need to make sure that initialization happens |
| - // properly. Possibly the right thing is to have the UI handle |
| - // this case specially. |
| - return; |
| + // Whoops. That didn't work. Proceed as an interrupted download. |
| + destination_error_ = result; |
| + TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL); |
| } |
| + DetermineDownloadTarget(); |
| +} |
| + |
| +void DownloadItemImpl::DetermineDownloadTarget() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + DVLOG(20) << __FUNCTION__ << "() " << DebugString(true); |
| + |
| delegate_->DetermineDownloadTarget( |
| this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| -// Called by delegate_ when the download target path has been |
| -// determined. |
| +// Called by delegate_ when the download target path has been determined. |
| void DownloadItemImpl::OnDownloadTargetDetermined( |
| const base::FilePath& target_path, |
| TargetDisposition disposition, |
| DownloadDangerType danger_type, |
| const base::FilePath& intermediate_path) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - DCHECK_EQ(state_, TARGET_PENDING_INTERNAL); |
| + DCHECK(state_ == TARGET_PENDING_INTERNAL || |
| + state_ == INTERRUPTED_TARGET_PENDING_INTERNAL); |
| // If the |target_path| is empty, then we consider this download to be |
| // canceled. |
| @@ -1204,21 +1250,23 @@ 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. |
| - |
| - DVLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition |
| - << " " << danger_type << " " << DebugString(true); |
| + DVLOG(20) << __FUNCTION__ << "() target_path:" << target_path.value() |
| + << " disposition:" << disposition << " danger_type:" << danger_type |
| + << " this:" << DebugString(true); |
| target_path_ = target_path; |
| target_disposition_ = disposition; |
| SetDangerType(danger_type); |
| + // This was an interrupted download that was looking for a filename. Now that |
| + // it has one, transition to interrupted. |
| + if (state_ == INTERRUPTED_TARGET_PENDING_INTERNAL) { |
| + Interrupt(destination_error_); |
| + destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE; |
| + UpdateObservers(); |
| + return; |
| + } |
| + |
| // We want the intermediate and target paths to refer to the same directory so |
| // that they are both on the same device and subject to same |
| // space/permission/availability constraints. |
| @@ -1261,7 +1309,7 @@ void DownloadItemImpl::OnDownloadRenamedToIntermediateName( |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| DCHECK_EQ(state_, TARGET_PENDING_INTERNAL); |
| DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); |
| - TransitionTo(TARGET_RESOLVED_INTERNAL, DONT_UPDATE_OBSERVERS); |
| + TransitionTo(TARGET_RESOLVED_INTERNAL); |
| if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) { |
| // Process destination error. If both |reason| and |destination_error_| |
| @@ -1271,15 +1319,19 @@ void DownloadItemImpl::OnDownloadRenamedToIntermediateName( |
| SetFullPath(full_path); |
| Interrupt(destination_error_); |
| destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE; |
| + UpdateObservers(); |
| } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
| Interrupt(reason); |
| // All file errors result in file deletion above; no need to cleanup. The |
| // current_path_ should be empty. Resuming this download will force a |
| // restart and a re-doing of filename determination. |
| DCHECK(current_path_.empty()); |
| + UpdateObservers(); |
| } else { |
| SetFullPath(full_path); |
| - TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS); |
| + TransitionTo(IN_PROGRESS_INTERNAL); |
| + UpdateObservers(); // TODO(asanka): This is not safe. The download could be |
| + // in an underminate state after invoking observers. |
|
Randy Smith (Not in Mondays)
2016/02/12 19:10:28
Unlike the other place where you have the same com
asanka
2016/02/12 19:30:35
Semantics are the same? I.e. both before and after
|
| MaybeCompleteDownload(); |
| } |
| } |
| @@ -1327,9 +1379,8 @@ void DownloadItemImpl::OnDownloadCompleting() { |
| // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration. |
| if (is_save_package_download_) { |
| // Avoid doing anything on the file thread; there's nothing we control |
| - // there. |
| - // Strictly speaking, this skips giving the embedder a chance to open |
| - // the download. But on a save package download, there's no real |
| + // there. Strictly speaking, this skips giving the embedder a chance to |
| + // open the download. But on a save package download, there's no real |
| // concept of opening. |
| Completed(); |
| return; |
| @@ -1370,6 +1421,7 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName( |
| // All file errors should have resulted in in file deletion above. On |
| // resumption we will need to re-do filename determination. |
| DCHECK(current_path_.empty()); |
| + UpdateObservers(); |
| return; |
| } |
| @@ -1389,7 +1441,7 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName( |
| // point we're committed to complete the download. Cancels (or Interrupts, |
| // though it's not clear how they could happen) after this point will be |
| // ignored. |
| - TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS); |
| + TransitionTo(COMPLETING_INTERNAL); |
| if (delegate_->ShouldOpenDownload( |
| this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened, |
| @@ -1415,7 +1467,7 @@ void DownloadItemImpl::Completed() { |
| DCHECK(all_data_saved_); |
| end_time_ = base::Time::Now(); |
| - TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS); |
| + TransitionTo(COMPLETE_INTERNAL); |
| RecordDownloadCompleted(start_tick_, received_bytes_); |
| if (auto_opened_) { |
| @@ -1430,24 +1482,8 @@ void DownloadItemImpl::Completed() { |
| OpenDownload(); |
| auto_opened_ = true; |
| - UpdateObservers(); |
| } |
| -} |
| - |
| -void DownloadItemImpl::OnResumeRequestStarted( |
| - DownloadItem* item, |
| - DownloadInterruptReason interrupt_reason) { |
| - // If |item| is not NULL, then Start() has been called already, and nothing |
| - // more needs to be done here. |
| - if (item) { |
| - DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); |
| - DCHECK_EQ(static_cast<DownloadItem*>(this), item); |
| - return; |
| - } |
| - // Otherwise, the request failed without passing through |
| - // DownloadResourceHandler::OnResponseStarted. |
| - DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); |
| - Interrupt(interrupt_reason); |
| + UpdateObservers(); |
| } |
| // **** End of Download progression cascade |
| @@ -1482,9 +1518,10 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { |
| NOTREACHED(); |
| return; |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
| + case IN_PROGRESS_INTERNAL: |
| case TARGET_PENDING_INTERNAL: |
|
Randy Smith (Not in Mondays)
2016/02/12 21:57:19
I thought we couldn't interrupt from TARGET_PENDIN
asanka
2016/02/12 23:34:47
It's not allowed. But we can transition to CANCELL
|
| case TARGET_RESOLVED_INTERNAL: |
| - case IN_PROGRESS_INTERNAL: |
| // last_reason_ needs to be set for GetResumeMode() to work. |
| last_reason_ = reason; |
| @@ -1542,16 +1579,16 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { |
| } |
| RecordDownloadCount(CANCELLED_COUNT); |
| - TransitionTo(CANCELLED_INTERNAL, DONT_UPDATE_OBSERVERS); |
| - } else { |
| - RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); |
| - if (!GetWebContents()) |
| - RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS); |
| - TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS); |
| - AutoResumeIfValid(); |
| + TransitionTo(CANCELLED_INTERNAL); |
| + return; |
| } |
| - UpdateObservers(); |
| + RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); |
| + if (!GetWebContents()) |
| + RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS); |
| + |
| + TransitionTo(INTERRUPTED_INTERNAL); |
| + AutoResumeIfValid(); |
| } |
| void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) { |
| @@ -1597,8 +1634,10 @@ bool DownloadItemImpl::IsDownloadReadyForCompletion( |
| if (IsDangerous()) |
| return false; |
| - // Invariants for the IN_PROGRESS state. DCHECKs here verify that the |
| - // invariants are still true. |
| + // Check for consistency before invoking delegate. Since there are no pending |
| + // target determination calls and the download is in progress, both the target |
| + // and current paths should be non-empty and they should point to the same |
| + // directory. |
| DCHECK(!target_path_.empty()); |
| DCHECK(!current_path_.empty()); |
| DCHECK(target_path_.DirName() == current_path_.DirName()); |
| @@ -1611,8 +1650,7 @@ bool DownloadItemImpl::IsDownloadReadyForCompletion( |
| return true; |
| } |
| -void DownloadItemImpl::TransitionTo(DownloadInternalState new_state, |
| - ShouldUpdateObservers notify_action) { |
| +void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (state_ == new_state) |
| @@ -1634,6 +1672,7 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state, |
| case TARGET_PENDING_INTERNAL: |
| case TARGET_RESOLVED_INTERNAL: |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
| break; |
| case IN_PROGRESS_INTERNAL: |
| @@ -1715,9 +1754,6 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state, |
| this, SRC_ACTIVE_DOWNLOAD, |
| &file_name)); |
| } |
| - |
| - if (notify_action == UPDATE_OBSERVERS) |
| - UpdateObservers(); |
| } |
| void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) { |
| @@ -1779,6 +1815,10 @@ void DownloadItemImpl::ResumeInterruptedDownload() { |
| if (state_ != INTERRUPTED_INTERNAL) |
| return; |
| + // We are starting a new request. Shake off all pending operations. |
| + DCHECK(!download_file_); |
| + weak_ptr_factory_.InvalidateWeakPtrs(); |
| + |
| // Reset the appropriate state if restarting. |
| ResumeMode mode = GetResumeMode(); |
| if (mode == RESUME_MODE_IMMEDIATE_RESTART || |
| @@ -1789,25 +1829,19 @@ void DownloadItemImpl::ResumeInterruptedDownload() { |
| etag_ = ""; |
| } |
| - scoped_ptr<DownloadUrlParameters> download_params; |
| - if (GetWebContents()) { |
| - download_params = |
| - DownloadUrlParameters::FromWebContents(GetWebContents(), GetURL()); |
| - } else { |
| - download_params = make_scoped_ptr(new DownloadUrlParameters( |
| - GetURL(), -1, -1, -1, GetBrowserContext()->GetResourceContext())); |
| - } |
| - |
| + // Avoid using the WebContents even if it's still around. Resumption requests |
| + // are consistently routed through the no-renderer code paths so that the |
| + // request will not be dropped if the WebContents (and by extension, the |
| + // associated renderer) goes away before a response is received. |
| + scoped_ptr<DownloadUrlParameters> download_params(new DownloadUrlParameters( |
| + GetURL(), -1, -1, -1, GetBrowserContext()->GetResourceContext())); |
| download_params->set_file_path(GetFullPath()); |
| download_params->set_offset(GetReceivedBytes()); |
| 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())); |
| - TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS); |
| + TransitionTo(RESUMING_INTERNAL); |
| delegate_->ResumeInterruptedDownload(std::move(download_params), GetId()); |
| // Just in case we were interrupted while paused. |
| is_paused_ = false; |
| @@ -1820,6 +1854,7 @@ DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( |
| case INITIAL_INTERNAL: |
| case TARGET_PENDING_INTERNAL: |
| case TARGET_RESOLVED_INTERNAL: |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
| // TODO(asanka): Introduce an externally visible state to distinguish |
| // between the above states and IN_PROGRESS_INTERNAL. The latter (the |
| // state where the download is active and has a known target) is the state |
| @@ -1870,6 +1905,7 @@ bool DownloadItemImpl::IsValidSavePackageStateTransition( |
| switch (from) { |
| case INITIAL_INTERNAL: |
| case TARGET_PENDING_INTERNAL: |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
| case TARGET_RESOLVED_INTERNAL: |
| case COMPLETING_INTERNAL: |
| case COMPLETE_INTERNAL: |
| @@ -1896,10 +1932,15 @@ bool DownloadItemImpl::IsValidStateTransition(DownloadInternalState from, |
| #if DCHECK_IS_ON() |
| switch (from) { |
| case INITIAL_INTERNAL: |
| - return to == TARGET_PENDING_INTERNAL || to == INTERRUPTED_INTERNAL; |
| + return to == TARGET_PENDING_INTERNAL || |
| + to == INTERRUPTED_TARGET_PENDING_INTERNAL; |
| case TARGET_PENDING_INTERNAL: |
| - return to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL; |
| + return to == INTERRUPTED_TARGET_PENDING_INTERNAL || |
| + to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL; |
| + |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
| + return to == INTERRUPTED_INTERNAL || to == CANCELLED_INTERNAL; |
| case TARGET_RESOLVED_INTERNAL: |
| return to == IN_PROGRESS_INTERNAL || to == INTERRUPTED_INTERNAL || |
| @@ -1919,7 +1960,9 @@ bool DownloadItemImpl::IsValidStateTransition(DownloadInternalState from, |
| return to == RESUMING_INTERNAL || to == CANCELLED_INTERNAL; |
| case RESUMING_INTERNAL: |
| - return to == TARGET_PENDING_INTERNAL || to == CANCELLED_INTERNAL; |
| + return to == TARGET_PENDING_INTERNAL || |
| + to == INTERRUPTED_TARGET_PENDING_INTERNAL || |
| + to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL; |
| case CANCELLED_INTERNAL: |
| return false; |
| @@ -1940,6 +1983,8 @@ const char* DownloadItemImpl::DebugDownloadStateString( |
| return "INITIAL"; |
| case TARGET_PENDING_INTERNAL: |
| return "TARGET_PENDING"; |
| + case INTERRUPTED_TARGET_PENDING_INTERNAL: |
| + return "INTERRUPTED_TARGET_PENDING"; |
| case TARGET_RESOLVED_INTERNAL: |
| return "TARGET_RESOLVED"; |
| case IN_PROGRESS_INTERNAL: |