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 ea39f32a214641d17265bc73a4104ba0f7c1ecf6..adc4bbc55c112cb1e89a0d5d3ddd7dab6cf068a0 100644 |
--- a/content/browser/download/download_item_impl.cc |
+++ b/content/browser/download/download_item_impl.cc |
@@ -80,22 +80,6 @@ const char* DebugSafetyStateString(DownloadItem::SafetyState state) { |
}; |
} |
-const char* DebugDownloadStateString(DownloadItem::DownloadState state) { |
- switch (state) { |
- case DownloadItem::IN_PROGRESS: |
- return "IN_PROGRESS"; |
- case DownloadItem::COMPLETE: |
- return "COMPLETE"; |
- case DownloadItem::CANCELLED: |
- return "CANCELLED"; |
- case DownloadItem::INTERRUPTED: |
- return "INTERRUPTED"; |
- default: |
- NOTREACHED() << "Unknown download state " << state; |
- return "unknown"; |
- }; |
-} |
- |
// Classes to null out request handle calls (for SavePage DownloadItems, which |
// may have, e.g., Cancel() called on them without it doing anything) |
// and to DCHECK on them (for history DownloadItems, which should never have |
@@ -135,6 +119,23 @@ const char DownloadItem::kEmptyFileHash[] = ""; |
} |
+const content::DownloadItem::DownloadState |
+DownloadItemImpl::kInternalStateMap[] = { |
+ content::DownloadItem::IN_PROGRESS, |
+ content::DownloadItem::IN_PROGRESS, |
+ content::DownloadItem::COMPLETE, |
+ content::DownloadItem::CANCELLED, |
+ content::DownloadItem::INTERRUPTED, |
+}; |
+ |
+const DownloadItemImpl::DownloadInternalState |
+DownloadItemImpl::kExternalStateMap[] = { |
+ DownloadItemImpl::IN_PROGRESS_INTERNAL, |
+ DownloadItemImpl::COMPLETE_INTERNAL, |
+ DownloadItemImpl::CANCELLED_INTERNAL, |
+ DownloadItemImpl::INTERRUPTED_INTERNAL, |
+}; |
+ |
// Our download table ID starts at 1, so we use 0 to represent a download that |
// has started, but has not yet had its data persisted in the table. We use fake |
// database handles in incognito mode starting at -1 and progressively getting |
@@ -158,7 +159,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, |
bytes_per_sec_(0), |
last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE), |
start_tick_(base::TimeTicks()), |
- state_(info.state), |
+ state_(kExternalStateMap[info.state]), |
danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), |
start_time_(info.start_time), |
end_time_(info.end_time), |
@@ -178,9 +179,9 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, |
bound_net_log_(bound_net_log), |
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
delegate_->Attach(); |
- if (IsInProgress()) |
- state_ = CANCELLED; |
- if (IsComplete()) |
+ if (state_ == IN_PROGRESS_INTERNAL) |
+ state_ = CANCELLED_INTERNAL; |
+ if (state_ == COMPLETE_INTERNAL) |
all_data_saved_ = true; |
Init(false /* not actively downloading */, |
download_net_logs::SRC_HISTORY_IMPORT); |
@@ -213,7 +214,7 @@ DownloadItemImpl::DownloadItemImpl( |
bytes_per_sec_(0), |
last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE), |
start_tick_(base::TimeTicks::Now()), |
- state_(IN_PROGRESS), |
+ state_(kExternalStateMap[IN_PROGRESS]), |
danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), |
start_time_(info.start_time), |
db_handle_(DownloadItem::kUninitializedHandle), |
@@ -268,7 +269,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, |
bytes_per_sec_(0), |
last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE), |
start_tick_(base::TimeTicks::Now()), |
- state_(IN_PROGRESS), |
+ state_(kExternalStateMap[IN_PROGRESS]), |
danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), |
start_time_(base::Time::Now()), |
db_handle_(DownloadItem::kUninitializedHandle), |
@@ -339,7 +340,7 @@ void DownloadItemImpl::DangerousDownloadValidated() { |
void DownloadItemImpl::TogglePause() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- DCHECK(IsInProgress()); |
+ DCHECK(state_ == IN_PROGRESS_INTERNAL || state_ == COMPLETING_INTERNAL); |
if (is_paused_) |
request_handle_->ResumeRequest(); |
else |
@@ -356,7 +357,7 @@ void DownloadItemImpl::Cancel(bool user_cancel) { |
content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN; |
VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
- if (!IsPartialDownload()) { |
+ if (state_ != IN_PROGRESS_INTERNAL) { |
// Small downloads might be complete before this method has |
// a chance to run. |
return; |
@@ -364,7 +365,7 @@ void DownloadItemImpl::Cancel(bool user_cancel) { |
download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); |
- TransitionTo(CANCELLED); |
+ TransitionTo(CANCELLED_INTERNAL); |
if (user_cancel) |
delegate_->DownloadStopped(this); |
} |
@@ -410,7 +411,7 @@ void DownloadItemImpl::Remove() { |
void DownloadItemImpl::OpenDownload() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (IsPartialDownload()) { |
+ if (state_ == IN_PROGRESS_INTERNAL) { |
// We don't honor the open_when_complete_ flag for temporary |
// downloads. Don't set it because it shows up in the UI. |
if (!IsTemporary()) |
@@ -418,7 +419,7 @@ void DownloadItemImpl::OpenDownload() { |
return; |
} |
- if (!IsComplete() || file_externally_removed_) |
+ if (!state_ == COMPLETE_INTERNAL || file_externally_removed_) |
benjhayden
2012/09/19 15:44:35
s/!state_ ==/state_ !=/
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
Whooops. Done.
|
return; |
// Ideally, we want to detect errors in opening and report them, but we |
@@ -458,7 +459,14 @@ int64 DownloadItemImpl::GetDbHandle() const { |
} |
DownloadItem::DownloadState DownloadItemImpl::GetState() const { |
- return state_; |
+ // Make sure the mapping arrays satisfy constraints. |
+ COMPILE_ASSERT(ARRAYSIZE_UNSAFE(kInternalStateMap) == |
benjhayden
2012/09/19 15:44:35
Could you put these up by the maps themselves?
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
I'd like to, but they need to be in the DownloadIt
|
+ MAX_DOWNLOAD_INTERNAL_STATE, |
+ internal_state_map_conflicts_with_states); |
+ COMPILE_ASSERT(ARRAYSIZE_UNSAFE(kExternalStateMap) == MAX_DOWNLOAD_STATE, |
+ external_state_map_conflicts_with_states); |
+ |
+ return kInternalStateMap[state_]; |
} |
content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const { |
@@ -480,24 +488,23 @@ bool DownloadItemImpl::IsPersisted() const { |
// TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to |
// |IsPartialDownload()|, when resuming interrupted downloads is implemented. |
bool DownloadItemImpl::IsPartialDownload() const { |
- return (state_ == IN_PROGRESS); |
+ return (state_ == IN_PROGRESS_INTERNAL); |
benjhayden
2012/09/19 15:44:35
Have you inspected all callers of IsPartialDownloa
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
Argggh. You triggerred my "not conceptually part
|
} |
bool DownloadItemImpl::IsInProgress() const { |
- return (state_ == IN_PROGRESS); |
+ return (state_ == IN_PROGRESS_INTERNAL || state_ == COMPLETING_INTERNAL); |
} |
bool DownloadItemImpl::IsCancelled() const { |
- return (state_ == CANCELLED) || |
- (state_ == INTERRUPTED); |
+ return (state_ == CANCELLED_INTERNAL || state_ == INTERRUPTED_INTERNAL); |
} |
bool DownloadItemImpl::IsInterrupted() const { |
- return (state_ == INTERRUPTED); |
+ return (state_ == INTERRUPTED_INTERNAL); |
} |
bool DownloadItemImpl::IsComplete() const { |
- return (state_ == COMPLETE); |
+ return (state_ == COMPLETE_INTERNAL); |
} |
const GURL& DownloadItemImpl::GetURL() const { |
@@ -670,7 +677,7 @@ base::Time DownloadItemImpl::GetEndTime() const { |
} |
bool DownloadItemImpl::CanShowInFolder() { |
- return !IsCancelled() && !file_externally_removed_; |
+ return state_ != CANCELLED_INTERNAL && !file_externally_removed_; |
} |
bool DownloadItemImpl::CanOpenDownload() { |
@@ -750,7 +757,7 @@ std::string DownloadItemImpl::DebugString(bool verbose) const { |
base::StringPrintf("{ id = %d" |
" state = %s", |
download_id_.local(), |
- DebugDownloadStateString(GetState())); |
+ DebugDownloadStateString(state_)); |
// Construct a string of the URL chain. |
std::string url_list("<none>"); |
@@ -834,11 +841,11 @@ void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { |
// interrupts to race with cancels. |
// Whatever happens, the first one to hit the UI thread wins. |
- if (!IsInProgress()) |
+ if (state_ != IN_PROGRESS_INTERNAL) |
return; |
last_reason_ = reason; |
- TransitionTo(INTERRUPTED); |
+ TransitionTo(INTERRUPTED_INTERNAL); |
download_stats::RecordDownloadInterrupted( |
reason, received_bytes_, total_bytes_); |
delegate_->DownloadStopped(this); |
@@ -856,7 +863,7 @@ void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, |
const std::string& hash_state) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (!IsInProgress()) { |
+ if (state_ != IN_PROGRESS_INTERNAL) { |
// Ignore if we're no longer in-progress. This can happen if we race a |
// Cancel on the UI thread with an update on the FILE thread. |
// |
@@ -901,7 +908,7 @@ void DownloadItemImpl::MarkAsComplete() { |
DCHECK(all_data_saved_); |
end_time_ = base::Time::Now(); |
- TransitionTo(COMPLETE); |
+ TransitionTo(COMPLETE_INTERNAL); |
} |
void DownloadItemImpl::SetIsPersisted() { |
@@ -986,6 +993,16 @@ void DownloadItemImpl::OnDownloadTargetDetermined( |
// space/permission/availability constraints. |
DCHECK(intermediate_path.DirName() == target_path.DirName()); |
+ if (!IsInProgress()) { |
benjhayden
2012/09/19 15:44:35
Why respell some IsInProgress()/IsComplete()/etc.
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
Agreed. I had thought I had replaced them all (I
|
+ // If we've been cancelled or interrupted while the target was being |
+ // determined, continue the cascade with a null name. |
+ // The error doesn't matter as the cause of download stoppaged |
benjhayden
2012/09/19 15:44:35
s/stoppaged/stoppage/
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
Done.
|
+ // will already have been recorded. |
benjhayden
2012/09/19 15:44:35
Could you convert "the cause of download stoppage"
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
I'm slightly confused by your question. My commen
|
+ OnDownloadRenamedToIntermediateName( |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, FilePath()); |
+ return; |
+ } |
+ |
// Rename to intermediate name. |
// TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a |
// spurious rename when we can just rename to the final |
@@ -1025,6 +1042,9 @@ void DownloadItemImpl::MaybeCompleteDownload() { |
void DownloadItemImpl::OnDownloadCompleting() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (!IsInProgress()) |
+ return; |
+ |
VLOG(20) << __FUNCTION__ << "()" |
<< " needs rename = " << NeedsRename() |
<< " " << DebugString(true); |
@@ -1048,6 +1068,7 @@ void DownloadItemImpl::OnDownloadCompleting() { |
delegate_->GetDownloadFileManager(), GetGlobalId(), |
base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
weak_ptr_factory_.GetWeakPtr()))); |
+ TransitionTo(COMPLETING_INTERNAL); |
} |
} |
@@ -1056,6 +1077,9 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName( |
const FilePath& full_path) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (!IsInProgress()) |
benjhayden
2012/09/19 15:44:35
So, if I cancel a download *while* it's being rena
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
Huh. Good point; at a minimum we should have a co
|
+ return; |
+ |
VLOG(20) << __FUNCTION__ << "()" |
<< " full_path = \"" << full_path.value() << "\"" |
<< " needed rename = " << NeedsRename() |
@@ -1080,6 +1104,7 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName( |
delegate_->GetDownloadFileManager(), GetGlobalId(), |
base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
weak_ptr_factory_.GetWeakPtr()))); |
+ TransitionTo(COMPLETING_INTERNAL); |
} |
void DownloadItemImpl::OnDownloadFileReleased() { |
@@ -1101,7 +1126,7 @@ void DownloadItemImpl::Completed() { |
DCHECK(all_data_saved_); |
end_time_ = base::Time::Now(); |
- TransitionTo(COMPLETE); |
+ TransitionTo(COMPLETE_INTERNAL); |
delegate_->DownloadCompleted(this); |
download_stats::RecordDownloadCompleted(start_tick_, received_bytes_); |
@@ -1143,27 +1168,33 @@ void DownloadItemImpl::ProgressComplete(int64 bytes_so_far, |
total_bytes_ = 0; |
} |
-void DownloadItemImpl::TransitionTo(DownloadState new_state) { |
+void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { |
if (state_ == new_state) |
return; |
- DownloadState old_state = state_; |
+ DownloadInternalState old_state = state_; |
state_ = new_state; |
switch (state_) { |
- case COMPLETE: |
+ case COMPLETING_INTERNAL: |
+ bound_net_log_.AddEvent( |
+ net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING, |
+ base::Bind(&download_net_logs::ItemCompletingCallback, |
+ received_bytes_, &hash_)); |
+ break; |
+ case COMPLETE_INTERNAL: |
bound_net_log_.AddEvent( |
net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED, |
base::Bind(&download_net_logs::ItemFinishedCallback, |
- received_bytes_, &hash_)); |
+ auto_opened_)); |
break; |
- case INTERRUPTED: |
+ case INTERRUPTED_INTERNAL: |
bound_net_log_.AddEvent( |
net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED, |
base::Bind(&download_net_logs::ItemInterruptedCallback, |
last_reason_, received_bytes_, &hash_state_)); |
break; |
- case CANCELLED: |
+ case CANCELLED_INTERNAL: |
bound_net_log_.AddEvent( |
net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED, |
base::Bind(&download_net_logs::ItemCanceledCallback, |
@@ -1175,10 +1206,14 @@ void DownloadItemImpl::TransitionTo(DownloadState new_state) { |
VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true); |
- UpdateObservers(); |
+ // Only update observers on user visible state changes. |
+ if (kInternalStateMap[old_state] != kInternalStateMap[state_]) |
benjhayden
2012/09/19 15:44:35
Should you use the state maps in IsInProgress()/Is
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
Could you put a few more words behind your argumen
|
+ UpdateObservers(); |
- bool is_done = (state_ != IN_PROGRESS); |
- bool was_done = (old_state != IN_PROGRESS); |
+ bool is_done = (state_ != IN_PROGRESS_INTERNAL && |
+ state_ != COMPLETING_INTERNAL); |
+ bool was_done = (old_state != IN_PROGRESS_INTERNAL && |
+ old_state != COMPLETING_INTERNAL); |
if (is_done && !was_done) |
bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE); |
} |
@@ -1212,6 +1247,26 @@ void DownloadItemImpl::SetFullPath(const FilePath& new_path) { |
¤t_path_, &new_path)); |
} |
+// static |
benjhayden
2012/09/19 15:44:35
What's the difference between a private static met
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
I originally followed your suggestion and took it
|
+const char* DownloadItemImpl::DebugDownloadStateString( |
+ DownloadInternalState state) { |
+ switch (state) { |
+ case IN_PROGRESS_INTERNAL: |
+ return "IN_PROGRESS"; |
+ case COMPLETING_INTERNAL: |
+ return "COMPLETING"; |
+ case COMPLETE_INTERNAL: |
+ return "COMPLETE"; |
+ case CANCELLED_INTERNAL: |
+ return "CANCELLED"; |
+ case INTERRUPTED_INTERNAL: |
+ return "INTERRUPTED"; |
+ default: |
+ NOTREACHED() << "Unknown download state " << state; |
+ return "unknown"; |
+ }; |
+} |
+ |
benjhayden
2012/09/19 15:44:35
Mind deleting all these blank lines?
Randy Smith (Not in Mondays)
2012/09/19 20:46:39
I'll have you know, I have a deep, sentimental att
|