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 ebef25349cd4f290f3437aae2158e8daa11d9bd5..285a40e3ab595a8854dc18956b06f1e15aa2039c 100644 |
--- a/content/browser/download/download_item_impl.cc |
+++ b/content/browser/download/download_item_impl.cc |
@@ -170,9 +170,9 @@ DownloadItemImpl::DownloadItemImpl( |
const net::BoundNetLog& bound_net_log) |
: is_save_package_download_(false), |
download_id_(download_id), |
- target_disposition_( |
- (info.save_info->prompt_for_save_location) ? |
- TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE), |
+ target_disposition_((info.save_info->prompt_for_save_location) |
+ ? TARGET_DISPOSITION_PROMPT |
+ : TARGET_DISPOSITION_OVERWRITE), |
url_chain_(info.url_chain), |
referrer_url_(info.referrer_url), |
suggested_filename_(base::UTF16ToUTF8(info.save_info->suggested_name)), |
@@ -201,7 +201,7 @@ DownloadItemImpl::DownloadItemImpl( |
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), |
@@ -341,8 +341,9 @@ void DownloadItemImpl::StealDangerousDownload( |
void DownloadItemImpl::Pause() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- // Ignore irrelevant states. |
- if (state_ != IN_PROGRESS_INTERNAL || is_paused_) |
+ // Ignore irrelevant states. Also ignore the call if there's no request |
+ // handle. |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
This sounds like it's trying to handle Pause() req
asanka
2014/03/19 20:37:06
Hmm. Good point. We could set is_paused_ and respe
Randy Smith (Not in Mondays)
2014/03/20 15:24:54
That's effectively accepting that we have a race a
asanka
2016/02/11 23:57:24
But that's not correct. We are no longer in a plac
Randy Smith (Not in Mondays)
2016/02/12 18:58:10
Ok. I'm good with your race handling suggestion e
asanka
2016/02/12 20:52:28
Time Of Check vs. Time Of Use. :-) Basically, the
|
+ if (state_ != IN_PROGRESS_INTERNAL || is_paused_ || !request_handle_) |
return; |
request_handle_->PauseRequest(); |
@@ -408,7 +409,7 @@ void DownloadItemImpl::Cancel(bool user_cancel) { |
if (!is_save_package_download_ && download_file_) |
ReleaseDownloadFile(true); |
- if (state_ == IN_PROGRESS_INTERNAL) { |
+ if (state_ == IN_PROGRESS_INTERNAL && request_handle_) { |
// Cancel the originating URL request unless it's already been cancelled |
// by interrupt. |
request_handle_->CancelRequest(); |
@@ -926,6 +927,7 @@ void DownloadItemImpl::MergeOriginInfoOnResume( |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
DCHECK_EQ(RESUMING_INTERNAL, state_); |
DCHECK(!new_create_info.url_chain.empty()); |
+ DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, new_create_info.interrupt_reason); |
// We are going to tack on any new redirects to our list of redirects. |
// When a download is resumed, the URL used for the resumption request is the |
@@ -1106,11 +1108,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(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
DCHECK(!download_file_.get()); |
- DCHECK(file.get()); |
- DCHECK(req_handle.get()); |
download_file_ = file.Pass(); |
request_handle_ = req_handle.Pass(); |
@@ -1123,6 +1124,24 @@ void DownloadItemImpl::Start( |
return; |
} |
+ DCHECK(state_ == IN_PROGRESS_INTERNAL || state_ == RESUMING_INTERNAL); |
+ if (new_create_info.interrupt_reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |
+ DCHECK(!download_file_.get()); |
+ // If the download failed, then skip the download_file_ initialization. It |
+ // isn't going to be used anyway. OnDownloadFileInitialized() handles all |
+ // interrupts that happen up until after download file initialization. Allow |
+ // it to handle the new interrupt as well. |
+ OnDownloadFileInitialized(new_create_info.interrupt_reason); |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
nit: Might want to change the name if we're expand
Randy Smith (Not in Mondays)
2014/03/20 15:24:54
Just noting you didn't respond to this nit (I don'
asanka
2016/02/11 23:57:24
Whoops. Missed. I'm doing a pass through the previ
|
+ return; |
+ } |
+ |
+ // Successful download start. |
+ DCHECK(download_file_.get()); |
+ DCHECK(request_handle_.get()); |
+ |
+ if (state_ == RESUMING_INTERNAL) |
+ MergeOriginInfoOnResume(new_create_info); |
+ |
TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS); |
BrowserThread::PostTask( |
@@ -1138,16 +1157,25 @@ void DownloadItemImpl::OnDownloadFileInitialized( |
DownloadInterruptReason result) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { |
+ // Either the download was interrupted at Start() or the download file |
+ // failed to initialize. Either way, the download will not transition to an |
+ // interrupted state. |
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; |
+ |
+ // The download may transition to RESUMING_INTERNAL as a result of the |
+ // Interrupt() call above if it was resumed automatically. If so, then |
+ // Start() is expected to be called again and the download progression |
+ // cascade will be redone. Therefore we are done for now. |
+ // |
+ // NOTE: The check below assumes that resumption doesn't call Start() |
+ // synchronously. If it did, then state_ may not be RESUMING_INTERNAL when |
+ // we get here. This constraint is currently enforced via a DCHECK in |
+ // Start() which requires that the download be in RESUMING_INTERNAL or |
+ // IN_PROGRESS_INTERNAL state when Start() is called. If Start() was called |
+ // synchronously, then the state of the DownloadItem would be |
+ // INTERRUPTED_INTERNAL. |
+ if (state_ == RESUMING_INTERNAL) |
+ return; |
} |
delegate_->DetermineDownloadTarget( |
@@ -1171,20 +1199,19 @@ 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); |
target_path_ = target_path; |
target_disposition_ = disposition; |
SetDangerType(danger_type); |
+ if (state_ != IN_PROGRESS_INTERNAL) { |
+ // The download could be already interrupted, in which case there's nothing |
+ // more we can do. Notify observers and quit the download progression |
+ // cascade. |
+ 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 |
@@ -1210,7 +1237,6 @@ void DownloadItemImpl::OnDownloadTargetDetermined( |
// filename. Unnecessary renames may cause bugs like |
// http://crbug.com/74187. |
DCHECK(!is_save_package_download_); |
- DCHECK(download_file_.get()); |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
Ok, I'm confused. It seems to me that if we're no
asanka
2014/03/19 20:37:06
Ah. The DCHECK removal was due to an interim chang
|
DownloadFile::RenameCompletionCallback callback = |
base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, |
weak_ptr_factory_.GetWeakPtr()); |
@@ -1403,22 +1429,6 @@ void DownloadItemImpl::Completed() { |
} |
} |
-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); |
-} |
- |
// **** End of Download progression cascade |
// An error occurred somewhere. |
@@ -1443,34 +1453,31 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { |
ResumeMode resume_mode = GetResumeMode(); |
- if (state_ == IN_PROGRESS_INTERNAL) { |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
So this change is removing a bit of redundancy fro
asanka
2014/03/19 20:37:06
The problem was the handling of downloads that wer
Randy Smith (Not in Mondays)
2014/03/20 15:24:54
We could do this, but my instinct is that we shoul
asanka
2016/02/11 23:57:24
New downloads that start in a failed state need to
Randy Smith (Not in Mondays)
2016/02/12 18:58:10
I feel absolutely no need to resolve this old phil
asanka
2016/02/12 20:52:28
Acknowledged.
|
- // Cancel (delete file) if: |
- // 1) we're going to restart. |
- // 2) Resumption isn't possible (download was cancelled or blocked due to |
- // security restrictions). |
- // 3) Resumption isn't enabled. |
- // No point in leaving data around we aren't going to use. |
+ // Cancel (delete file) if: |
+ // 1) we're going to restart. |
+ // 2) Resumption isn't possible (download was cancelled or blocked due to |
+ // security restrictions). |
+ // 3) Resumption isn't enabled. |
+ // No point in leaving data around we aren't going to use. |
+ if (download_file_.get()) |
ReleaseDownloadFile(resume_mode == RESUME_MODE_IMMEDIATE_RESTART || |
resume_mode == RESUME_MODE_USER_RESTART || |
resume_mode == RESUME_MODE_INVALID || |
!IsDownloadResumptionEnabled()); |
- // Cancel the originating URL request. |
+ // Cancel the originating URL request. |
+ if (request_handle_.get()) |
request_handle_->CancelRequest(); |
- } else { |
- DCHECK(!download_file_.get()); |
- } |
- // Reset all data saved, as even if we did save all the data we're going |
- // to go through another round of downloading when we resume. |
- // There's a potential problem here in the abstract, as if we did download |
- // all the data and then run into a continuable error, on resumption we |
- // won't download any more data. However, a) there are currently no |
- // continuable errors that can occur after we download all the data, and |
- // b) if there were, that would probably simply result in a null range |
- // request, which would generate a DestinationCompleted() notification |
- // from the DownloadFile, which would behave properly with setting |
- // all_data_saved_ to false here. |
+ // Reset all data saved, as even if we did save all the data we're going to go |
+ // through another round of downloading when we resume. There's a potential |
+ // problem here in the abstract, as if we did download all the data and then |
+ // run into a continuable error, on resumption we won't download any more |
+ // data. However, a) there are currently no continuable errors that can occur |
+ // after we download all the data, and b) if there were, that would probably |
+ // simply result in a null range request, which would generate a |
+ // DestinationCompleted() notification from the DownloadFile, which would |
+ // behave properly with setting all_data_saved_ to false here. |
all_data_saved_ = false; |
TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS); |
@@ -1701,9 +1708,6 @@ 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())); |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
Isn't this assuming that neither of the fall-throu
asanka
2014/03/19 20:37:06
I verified that ResourceHandler::OnResponseComplet
Randy Smith (Not in Mondays)
2014/03/20 18:04:46
What about the places outside DownloadResourceHand
asanka
2016/02/11 23:57:24
RDH::BeginDownload doesn't call the started callba
|
delegate_->ResumeInterruptedDownload(download_params.Pass(), GetId()); |
// Just in case we were interrupted while paused. |