| 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 3c9521d314180cf38803328d6e5e1da5d7dda4e0..1912cce88b283dea91def38489559dbdd450e6be 100644
|
| --- a/content/browser/download/download_item_impl.cc
|
| +++ b/content/browser/download/download_item_impl.cc
|
| @@ -489,8 +489,19 @@ void DownloadItemImpl::Cancel(bool user_cancel) {
|
|
|
| // An error occurred somewhere.
|
| void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) {
|
| - // It should not be possible both to have an error and complete.
|
| - DCHECK(IsInProgress());
|
| + // 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
|
| + // interrupts from disk writes go through two different mechanisms (driven
|
| + // by rename requests from UI thread and by write requests from IO thread,
|
| + // respectively), and since we choose not to keep state on the File thread,
|
| + // this is the place where the races collide. It's also possible for
|
| + // interrupts to race with cancels.
|
| +
|
| + // Whatever happens, the first one to hit the UI thread wins.
|
| + if (!IsInProgress())
|
| + return;
|
| +
|
| last_reason_ = reason;
|
| TransitionTo(INTERRUPTED);
|
| download_stats::RecordDownloadInterrupted(
|
| @@ -739,6 +750,7 @@ void DownloadItemImpl::OnDownloadCompleting(DownloadFileManager* file_manager) {
|
|
|
| void DownloadItemImpl::OnDownloadRenamedToFinalName(
|
| DownloadFileManager* file_manager,
|
| + content::DownloadInterruptReason reason,
|
| const FilePath& full_path) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| @@ -748,12 +760,13 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
|
| << " " << DebugString(false);
|
| DCHECK(NeedsRename());
|
|
|
| - if (full_path.empty())
|
| - // Indicates error; also reported
|
| - // by DownloadManagerImpl::OnDownloadInterrupted.
|
| + if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
|
| + Interrupt(reason);
|
| return;
|
| + }
|
|
|
| // full_path is now the current and target file path.
|
| + DCHECK(!full_path.empty());
|
| target_path_ = full_path;
|
| SetFullPath(full_path);
|
| delegate_->DownloadRenamedToFinalName(this);
|
| @@ -775,12 +788,16 @@ void DownloadItemImpl::OnDownloadFileReleased() {
|
| }
|
|
|
| void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
|
| + content::DownloadInterruptReason reason,
|
| const FilePath& full_path) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - if (!full_path.empty()) {
|
| + if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
|
| + Interrupt(reason);
|
| + } else {
|
| SetFullPath(full_path);
|
| UpdateObservers();
|
| }
|
| +
|
| delegate_->DownloadRenamedToIntermediateName(this);
|
| }
|
|
|
|
|