OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // File method ordering: Methods in this file are in the same order as | 5 // File method ordering: Methods in this file are in the same order as |
6 // in download_item_impl.h, with the following exception: The public | 6 // in download_item_impl.h, with the following exception: The public |
7 // interface Start is placed in chronological order with the other | 7 // interface Start is placed in chronological order with the other |
8 // (private) routines that together define a DownloadItem's state | 8 // (private) routines that together define a DownloadItem's state |
9 // transitions as the download progresses. See "Download progression | 9 // transitions as the download progresses. See "Download progression |
10 // cascade" later in this file. | 10 // cascade" later in this file. |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
160 bound_net_log_(bound_net_log), | 160 bound_net_log_(bound_net_log), |
161 weak_ptr_factory_(this) { | 161 weak_ptr_factory_(this) { |
162 delegate_->Attach(); | 162 delegate_->Attach(); |
163 DCHECK_NE(IN_PROGRESS_INTERNAL, state_); | 163 DCHECK_NE(IN_PROGRESS_INTERNAL, state_); |
164 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT); | 164 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT); |
165 } | 165 } |
166 | 166 |
167 // Constructing for a regular download: | 167 // Constructing for a regular download: |
168 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, | 168 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, |
169 uint32_t download_id, | 169 uint32_t download_id, |
170 const DownloadCreateInfo& info, | 170 const DownloadCreateInfo& info, |
Randy Smith (Not in Mondays)
2016/02/10 21:48:45
Now that DII::Start() takes a DCI, is it possible
asanka
2016/02/11 03:43:07
It is in fact possible since the state of the down
| |
171 const net::BoundNetLog& bound_net_log) | 171 const net::BoundNetLog& bound_net_log) |
172 : is_save_package_download_(false), | 172 : is_save_package_download_(false), |
173 download_id_(download_id), | 173 download_id_(download_id), |
174 target_disposition_((info.save_info->prompt_for_save_location) | 174 target_disposition_((info.save_info->prompt_for_save_location) |
175 ? TARGET_DISPOSITION_PROMPT | 175 ? TARGET_DISPOSITION_PROMPT |
176 : TARGET_DISPOSITION_OVERWRITE), | 176 : TARGET_DISPOSITION_OVERWRITE), |
177 url_chain_(info.url_chain), | 177 url_chain_(info.url_chain), |
178 referrer_url_(info.referrer_url), | 178 referrer_url_(info.referrer_url), |
179 tab_url_(info.tab_url), | 179 tab_url_(info.tab_url), |
180 tab_referrer_url_(info.tab_referrer_url), | 180 tab_referrer_url_(info.tab_referrer_url), |
181 suggested_filename_(base::UTF16ToUTF8(info.save_info->suggested_name)), | 181 suggested_filename_(base::UTF16ToUTF8(info.save_info->suggested_name)), |
182 forced_file_path_(info.save_info->file_path), | 182 forced_file_path_(info.save_info->file_path), |
183 transition_type_(info.transition_type), | 183 transition_type_(info.transition_type), |
184 has_user_gesture_(info.has_user_gesture), | 184 has_user_gesture_(info.has_user_gesture), |
185 content_disposition_(info.content_disposition), | 185 content_disposition_(info.content_disposition), |
186 mime_type_(info.mime_type), | 186 mime_type_(info.mime_type), |
187 original_mime_type_(info.original_mime_type), | 187 original_mime_type_(info.original_mime_type), |
188 remote_address_(info.remote_address), | 188 remote_address_(info.remote_address), |
189 total_bytes_(info.total_bytes), | 189 total_bytes_(info.total_bytes), |
190 received_bytes_(0), | 190 received_bytes_(0), |
191 bytes_per_sec_(0), | 191 bytes_per_sec_(0), |
192 last_modified_time_(info.last_modified), | 192 last_modified_time_(info.last_modified), |
193 etag_(info.etag), | 193 etag_(info.etag), |
194 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE), | 194 last_reason_(info.result), |
195 start_tick_(base::TimeTicks::Now()), | 195 start_tick_(base::TimeTicks::Now()), |
196 state_(IN_PROGRESS_INTERNAL), | 196 state_(info.result == DOWNLOAD_INTERRUPT_REASON_NONE |
197 ? IN_PROGRESS_INTERNAL | |
198 : INTERRUPTED_INTERNAL), | |
197 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), | 199 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), |
198 start_time_(info.start_time), | 200 start_time_(info.start_time), |
199 delegate_(delegate), | 201 delegate_(delegate), |
200 is_paused_(false), | 202 is_paused_(false), |
201 auto_resume_count_(0), | 203 auto_resume_count_(0), |
202 open_when_complete_(false), | 204 open_when_complete_(false), |
203 file_externally_removed_(false), | 205 file_externally_removed_(false), |
204 auto_opened_(false), | 206 auto_opened_(false), |
205 is_temporary_(!info.save_info->file_path.empty()), | 207 is_temporary_(!info.save_info->file_path.empty()), |
206 all_data_saved_(false), | 208 all_data_saved_(false), |
207 destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE), | 209 destination_error_(DOWNLOAD_INTERRUPT_REASON_NONE), |
208 opened_(false), | 210 opened_(false), |
209 delegate_delayed_complete_(false), | 211 delegate_delayed_complete_(false), |
210 bound_net_log_(bound_net_log), | 212 bound_net_log_(bound_net_log), |
211 weak_ptr_factory_(this) { | 213 weak_ptr_factory_(this) { |
212 delegate_->Attach(); | 214 delegate_->Attach(); |
213 Init(true /* actively downloading */, SRC_ACTIVE_DOWNLOAD); | 215 Init(state_ == IN_PROGRESS_INTERNAL /* actively downloading */, |
216 SRC_ACTIVE_DOWNLOAD); | |
214 | 217 |
215 // Link the event sources. | 218 // Link the event sources. |
216 bound_net_log_.AddEvent( | 219 bound_net_log_.AddEvent( |
217 net::NetLog::TYPE_DOWNLOAD_URL_REQUEST, | 220 net::NetLog::TYPE_DOWNLOAD_URL_REQUEST, |
218 info.request_bound_net_log.source().ToEventParametersCallback()); | 221 info.request_bound_net_log.source().ToEventParametersCallback()); |
219 | 222 |
220 info.request_bound_net_log.AddEvent( | 223 info.request_bound_net_log.AddEvent( |
221 net::NetLog::TYPE_DOWNLOAD_STARTED, | 224 net::NetLog::TYPE_DOWNLOAD_STARTED, |
222 bound_net_log_.source().ToEventParametersCallback()); | 225 bound_net_log_.source().ToEventParametersCallback()); |
223 } | 226 } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
348 if (state_ != IN_PROGRESS_INTERNAL || is_paused_) | 351 if (state_ != IN_PROGRESS_INTERNAL || is_paused_) |
349 return; | 352 return; |
350 | 353 |
351 request_handle_->PauseRequest(); | 354 request_handle_->PauseRequest(); |
352 is_paused_ = true; | 355 is_paused_ = true; |
353 UpdateObservers(); | 356 UpdateObservers(); |
354 } | 357 } |
355 | 358 |
356 void DownloadItemImpl::Resume() { | 359 void DownloadItemImpl::Resume() { |
357 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 360 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
361 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); | |
358 switch (state_) { | 362 switch (state_) { |
359 case IN_PROGRESS_INTERNAL: | 363 case IN_PROGRESS_INTERNAL: |
360 if (!is_paused_) | 364 if (!is_paused_) |
361 return; | 365 return; |
362 request_handle_->ResumeRequest(); | 366 request_handle_->ResumeRequest(); |
363 is_paused_ = false; | 367 is_paused_ = false; |
364 UpdateObservers(); | 368 UpdateObservers(); |
365 return; | 369 return; |
366 | 370 |
367 case COMPLETING_INTERNAL: | 371 case COMPLETING_INTERNAL: |
368 case COMPLETE_INTERNAL: | 372 case COMPLETE_INTERNAL: |
369 case CANCELLED_INTERNAL: | 373 case CANCELLED_INTERNAL: |
370 case RESUMING_INTERNAL: | 374 case RESUMING_INTERNAL: |
371 return; | 375 return; |
372 | 376 |
373 case INTERRUPTED_INTERNAL: | 377 case INTERRUPTED_INTERNAL: |
374 auto_resume_count_ = 0; // User input resets the counter. | 378 auto_resume_count_ = 0; // User input resets the counter. |
375 ResumeInterruptedDownload(); | 379 ResumeInterruptedDownload(); |
380 UpdateObservers(); | |
376 return; | 381 return; |
377 | 382 |
378 case MAX_DOWNLOAD_INTERNAL_STATE: | 383 case MAX_DOWNLOAD_INTERNAL_STATE: |
379 NOTREACHED(); | 384 NOTREACHED(); |
380 } | 385 } |
381 } | 386 } |
382 | 387 |
383 void DownloadItemImpl::Cancel(bool user_cancel) { | 388 void DownloadItemImpl::Cancel(bool user_cancel) { |
384 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 389 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
385 | 390 |
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
918 case DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED: | 923 case DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED: |
919 case DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM: | 924 case DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM: |
920 case DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN: | 925 case DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN: |
921 mode = RESUME_MODE_INVALID; | 926 mode = RESUME_MODE_INVALID; |
922 break; | 927 break; |
923 } | 928 } |
924 | 929 |
925 return mode; | 930 return mode; |
926 } | 931 } |
927 | 932 |
928 void DownloadItemImpl::MergeOriginInfoOnResume( | 933 void DownloadItemImpl::UpdateValidatorsOnResumption( |
929 const DownloadCreateInfo& new_create_info) { | 934 const DownloadCreateInfo& new_create_info) { |
930 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 935 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
931 DCHECK_EQ(RESUMING_INTERNAL, state_); | 936 DCHECK_EQ(RESUMING_INTERNAL, state_); |
932 DCHECK(!new_create_info.url_chain.empty()); | |
933 | 937 |
934 // We are going to tack on any new redirects to our list of redirects. | 938 // Redirects are disallowed for a resumption request. |
935 // When a download is resumed, the URL used for the resumption request is the | 939 DCHECK_EQ(1u, new_create_info.url_chain.size()); |
936 // one at the end of the previous redirect chain. Tacking additional redirects | 940 DCHECK_EQ(url_chain_.back(), new_create_info.url_chain.back()); |
Randy Smith (Not in Mondays)
2016/02/10 21:48:45
So I could be misunderstand the code, but it seems
asanka
2016/02/11 03:43:07
This is asserted by DownloadRequestCore which inte
| |
937 // to the end of this chain ensures that: | |
938 // - If the download needs to be resumed again, the ETag/Last-Modified headers | |
939 // will be used with the last server that sent them to us. | |
940 // - The redirect chain contains all the servers that were involved in this | |
941 // download since the initial request, in order. | |
942 std::vector<GURL>::const_iterator chain_iter = | |
943 new_create_info.url_chain.begin(); | |
944 if (*chain_iter == url_chain_.back()) | |
945 ++chain_iter; | |
946 | 941 |
947 // Record some stats. If the precondition failed (the server returned | 942 // Record some stats. If the precondition failed (the server returned |
948 // HTTP_PRECONDITION_FAILED), then the download will automatically retried as | 943 // HTTP_PRECONDITION_FAILED), then the download will automatically retried as |
949 // a full request rather than a partial. Full restarts clobber validators. | 944 // a full request rather than a partial. Full restarts clobber validators. |
950 int origin_state = 0; | 945 int origin_state = 0; |
951 if (chain_iter != new_create_info.url_chain.end()) | |
952 origin_state |= ORIGIN_STATE_ON_RESUMPTION_ADDITIONAL_REDIRECTS; | |
953 if (etag_ != new_create_info.etag || | 946 if (etag_ != new_create_info.etag || |
954 last_modified_time_ != new_create_info.last_modified) | 947 last_modified_time_ != new_create_info.last_modified) |
955 origin_state |= ORIGIN_STATE_ON_RESUMPTION_VALIDATORS_CHANGED; | 948 origin_state |= ORIGIN_STATE_ON_RESUMPTION_VALIDATORS_CHANGED; |
956 if (content_disposition_ != new_create_info.content_disposition) | 949 if (content_disposition_ != new_create_info.content_disposition) |
957 origin_state |= ORIGIN_STATE_ON_RESUMPTION_CONTENT_DISPOSITION_CHANGED; | 950 origin_state |= ORIGIN_STATE_ON_RESUMPTION_CONTENT_DISPOSITION_CHANGED; |
958 RecordOriginStateOnResumption(new_create_info.save_info->offset != 0, | 951 RecordOriginStateOnResumption(new_create_info.save_info->offset != 0, |
959 origin_state); | 952 origin_state); |
960 | 953 |
961 url_chain_.insert( | |
962 url_chain_.end(), chain_iter, new_create_info.url_chain.end()); | |
963 etag_ = new_create_info.etag; | 954 etag_ = new_create_info.etag; |
964 last_modified_time_ = new_create_info.last_modified; | 955 last_modified_time_ = new_create_info.last_modified; |
965 content_disposition_ = new_create_info.content_disposition; | 956 content_disposition_ = new_create_info.content_disposition; |
966 | 957 |
967 // Don't update observers. This method is expected to be called just before a | 958 // Don't update observers. This method is expected to be called just before a |
968 // DownloadFile is created and Start() is called. The observers will be | 959 // DownloadFile is created and Start() is called. The observers will be |
969 // notified when the download transitions to the IN_PROGRESS state. | 960 // notified when the download transitions to the IN_PROGRESS state. |
970 } | 961 } |
971 | 962 |
972 void DownloadItemImpl::NotifyRemoved() { | 963 void DownloadItemImpl::NotifyRemoved() { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1053 UpdateObservers(); | 1044 UpdateObservers(); |
1054 } | 1045 } |
1055 | 1046 |
1056 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) { | 1047 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) { |
1057 // Postpone recognition of this error until after file name determination | 1048 // Postpone recognition of this error until after file name determination |
1058 // has completed and the intermediate file has been renamed to simplify | 1049 // has completed and the intermediate file has been renamed to simplify |
1059 // resumption conditions. | 1050 // resumption conditions. |
1060 if (current_path_.empty() || target_path_.empty()) | 1051 if (current_path_.empty() || target_path_.empty()) |
1061 destination_error_ = reason; | 1052 destination_error_ = reason; |
1062 else | 1053 else |
1063 Interrupt(reason); | 1054 Interrupt(reason, UPDATE_OBSERVERS); |
1064 } | 1055 } |
1065 | 1056 |
1066 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { | 1057 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { |
1067 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); | 1058 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); |
1068 if (GetState() != IN_PROGRESS) | 1059 if (GetState() != IN_PROGRESS) |
1069 return; | 1060 return; |
1070 OnAllDataSaved(final_hash); | 1061 OnAllDataSaved(final_hash); |
1071 MaybeCompleteDownload(); | 1062 MaybeCompleteDownload(); |
1072 } | 1063 } |
1073 | 1064 |
(...skipping 30 matching lines...) Expand all Loading... | |
1104 bound_net_log_.AddEvent( | 1095 bound_net_log_.AddEvent( |
1105 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data); | 1096 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data); |
1106 } | 1097 } |
1107 | 1098 |
1108 DVLOG(20) << __FUNCTION__ << "() " << DebugString(true); | 1099 DVLOG(20) << __FUNCTION__ << "() " << DebugString(true); |
1109 } | 1100 } |
1110 | 1101 |
1111 // We're starting the download. | 1102 // We're starting the download. |
1112 void DownloadItemImpl::Start( | 1103 void DownloadItemImpl::Start( |
1113 scoped_ptr<DownloadFile> file, | 1104 scoped_ptr<DownloadFile> file, |
1114 scoped_ptr<DownloadRequestHandleInterface> req_handle) { | 1105 scoped_ptr<DownloadRequestHandleInterface> req_handle, |
1106 const DownloadCreateInfo& new_create_info) { | |
1115 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1107 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
1116 DCHECK(!download_file_.get()); | 1108 DCHECK(!download_file_.get()); |
1117 DCHECK(file.get()); | |
1118 DCHECK(req_handle.get()); | |
1119 | 1109 |
1120 download_file_ = std::move(file); | 1110 download_file_ = std::move(file); |
1121 request_handle_ = std::move(req_handle); | 1111 request_handle_ = std::move(req_handle); |
1122 | 1112 |
1123 if (GetState() == CANCELLED) { | 1113 if (GetState() == CANCELLED) { |
1124 // The download was in the process of resuming when it was cancelled. Don't | 1114 // The download was in the process of resuming when it was cancelled. Don't |
1125 // proceed. | 1115 // proceed. |
1126 ReleaseDownloadFile(true); | 1116 ReleaseDownloadFile(true); |
1127 request_handle_->CancelRequest(); | 1117 request_handle_->CancelRequest(); |
1128 return; | 1118 return; |
1129 } | 1119 } |
1130 | 1120 |
1121 // The state could be one of the following: | |
1122 // | |
1123 // IN_PROGRESS_INTERNAL: Download started normally. | |
1124 // | |
1125 // RESUMING_INTERNAL: A resumption attempt. May or may not have been | |
1126 // successful. | |
1127 // | |
1128 // INTERRUPTED_INTERNAL: Download was DOA. (E.g. a programmatic download that | |
1129 // encountered a network error and didn't progress to the point where a | |
1130 // server response was available, or the server responded with an error). | |
1131 DCHECK(state_ == IN_PROGRESS_INTERNAL || state_ == RESUMING_INTERNAL || | |
1132 state_ == INTERRUPTED_INTERNAL); | |
1133 | |
1134 // If a resumption attempted failed, then the download goes back to being | |
1135 // interrupted. | |
1136 if (state_ == RESUMING_INTERNAL && | |
1137 new_create_info.result != DOWNLOAD_INTERRUPT_REASON_NONE) { | |
1138 DCHECK(!download_file_.get()); | |
1139 | |
1140 Interrupt(new_create_info.result, DONT_UPDATE_OBSERVERS); | |
1141 | |
1142 // Transitioning to interrupted may trigger another resumption attempt. If | |
1143 // so, Start() will be called again once a response is available for that | |
1144 // request. Nothing more needs to be done now. Note that Start() is never | |
1145 // called synchronously. | |
1146 if (state_ == RESUMING_INTERNAL) | |
1147 return; | |
1148 | |
1149 // Otherwise, the download should now be interrupted. | |
1150 DCHECK_EQ(INTERRUPTED_INTERNAL, state_); | |
1151 } | |
1152 | |
1153 if (state_ == INTERRUPTED_INTERNAL) { | |
1154 DCHECK(!download_file_.get()); | |
1155 // If the download failed, then skip the download_file_ initialization. It | |
1156 // isn't going to be used anyway. | |
1157 DetermineDownloadTarget(); | |
1158 return; | |
1159 } | |
1160 | |
1161 // Successful download start. | |
1162 DCHECK(download_file_.get()); | |
1163 DCHECK(request_handle_.get()); | |
1164 | |
1165 if (state_ == RESUMING_INTERNAL) | |
1166 UpdateValidatorsOnResumption(new_create_info); | |
1167 | |
1131 TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS); | 1168 TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS); |
1132 | 1169 |
1133 BrowserThread::PostTask( | 1170 BrowserThread::PostTask( |
1134 BrowserThread::FILE, FROM_HERE, | 1171 BrowserThread::FILE, FROM_HERE, |
1135 base::Bind(&DownloadFile::Initialize, | 1172 base::Bind(&DownloadFile::Initialize, |
1136 // Safe because we control download file lifetime. | 1173 // Safe because we control download file lifetime. |
1137 base::Unretained(download_file_.get()), | 1174 base::Unretained(download_file_.get()), |
1138 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, | 1175 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, |
1139 weak_ptr_factory_.GetWeakPtr()))); | 1176 weak_ptr_factory_.GetWeakPtr()))); |
1140 } | 1177 } |
1141 | 1178 |
1142 void DownloadItemImpl::OnDownloadFileInitialized( | 1179 void DownloadItemImpl::OnDownloadFileInitialized( |
1143 DownloadInterruptReason result) { | 1180 DownloadInterruptReason result) { |
1144 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1181 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
1145 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { | 1182 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { |
1146 Interrupt(result); | 1183 // The download file failed to initialize. |
1147 // TODO(rdsmith/asanka): Arguably we should show this in the UI, but | 1184 Interrupt(result, DONT_UPDATE_OBSERVERS); |
1148 // it's not at all clear what to show--we haven't done filename | 1185 |
1149 // determination, so we don't know what name to display. OTOH, | 1186 // The download may transition to RESUMING_INTERNAL as a result of the |
1150 // the failure mode of not showing the DI if the file initialization | 1187 // Interrupt() call above if it was resumed automatically. If so, then |
1151 // fails isn't a good one. Can we hack up a name based on the | 1188 // Start() is expected to be called again and the download progression |
1152 // URLRequest? We'll need to make sure that initialization happens | 1189 // cascade will be redone. Therefore we are done for now. Start() is never |
1153 // properly. Possibly the right thing is to have the UI handle | 1190 // called synchronously. |
1154 // this case specially. | 1191 if (state_ == RESUMING_INTERNAL) |
1155 return; | 1192 return; |
1156 } | 1193 } |
1157 | 1194 |
1195 DetermineDownloadTarget(); | |
Randy Smith (Not in Mondays)
2016/02/05 00:51:41
Random thought: Reading through this code, I'm str
asanka
2016/02/11 03:43:07
This is true. I'm also tempted to pull out the dow
| |
1196 } | |
1197 | |
1198 void DownloadItemImpl::DetermineDownloadTarget() { | |
1158 delegate_->DetermineDownloadTarget( | 1199 delegate_->DetermineDownloadTarget( |
1159 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined, | 1200 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined, |
1160 weak_ptr_factory_.GetWeakPtr())); | 1201 weak_ptr_factory_.GetWeakPtr())); |
1161 } | 1202 } |
1162 | 1203 |
1163 // Called by delegate_ when the download target path has been | 1204 // Called by delegate_ when the download target path has been |
1164 // determined. | 1205 // determined. |
1165 void DownloadItemImpl::OnDownloadTargetDetermined( | 1206 void DownloadItemImpl::OnDownloadTargetDetermined( |
1166 const base::FilePath& target_path, | 1207 const base::FilePath& target_path, |
1167 TargetDisposition disposition, | 1208 TargetDisposition disposition, |
1168 DownloadDangerType danger_type, | 1209 DownloadDangerType danger_type, |
1169 const base::FilePath& intermediate_path) { | 1210 const base::FilePath& intermediate_path) { |
1170 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1211 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
1171 | 1212 |
1172 // If the |target_path| is empty, then we consider this download to be | 1213 // If the |target_path| is empty, then we consider this download to be |
1173 // canceled. | 1214 // canceled. |
1174 if (target_path.empty()) { | 1215 if (target_path.empty()) { |
1175 Cancel(true); | 1216 Cancel(true); |
1176 return; | 1217 return; |
1177 } | 1218 } |
1178 | 1219 |
1179 // TODO(rdsmith,asanka): We are ignoring the possibility that the download | |
1180 // has been interrupted at this point until we finish the intermediate | |
1181 // rename and set the full path. That's dangerous, because we might race | |
1182 // with resumption, either manual (because the interrupt is visible to the | |
1183 // UI) or automatic. If we keep the "ignore an error on download until file | |
1184 // name determination complete" semantics, we need to make sure that the | |
1185 // error is kept completely invisible until that point. | |
1186 | |
1187 DVLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition | 1220 DVLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition |
1188 << " " << danger_type << " " << DebugString(true); | 1221 << " " << danger_type << " " << DebugString(true); |
1189 | 1222 |
1190 target_path_ = target_path; | 1223 target_path_ = target_path; |
1191 target_disposition_ = disposition; | 1224 target_disposition_ = disposition; |
1192 SetDangerType(danger_type); | 1225 SetDangerType(danger_type); |
1226 if (state_ != IN_PROGRESS_INTERNAL) { | |
1227 DCHECK(!download_file_); | |
1228 // Already interrupted or cancelled. Since there's now a filename for | |
1229 // display purposes, observers can be safely notified of the new [failed] | |
1230 // download. Nothing more needs to be done since there's no active request | |
1231 // or in-use file. | |
Randy Smith (Not in Mondays)
2016/02/05 00:51:41
Possible alternative implementation: Create a new
asanka
2016/02/11 03:43:07
Yup. That's what I ended up doing, partly to deal
| |
1232 UpdateObservers(); | |
1233 return; | |
1234 } | |
1193 | 1235 |
1194 // We want the intermediate and target paths to refer to the same directory so | 1236 // We want the intermediate and target paths to refer to the same directory so |
1195 // that they are both on the same device and subject to same | 1237 // that they are both on the same device and subject to same |
1196 // space/permission/availability constraints. | 1238 // space/permission/availability constraints. |
1197 DCHECK(intermediate_path.DirName() == target_path.DirName()); | 1239 DCHECK(intermediate_path.DirName() == target_path.DirName()); |
1198 | 1240 |
1199 // During resumption, we may choose to proceed with the same intermediate | 1241 // During resumption, we may choose to proceed with the same intermediate |
1200 // file. No rename is necessary if our intermediate file already has the | 1242 // file. No rename is necessary if our intermediate file already has the |
1201 // correct name. | 1243 // correct name. |
1202 // | 1244 // |
(...skipping 29 matching lines...) Expand all Loading... | |
1232 const base::FilePath& full_path) { | 1274 const base::FilePath& full_path) { |
1233 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1275 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
1234 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); | 1276 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); |
1235 | 1277 |
1236 if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) { | 1278 if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) { |
1237 // Process destination error. If both |reason| and |destination_error_| | 1279 // Process destination error. If both |reason| and |destination_error_| |
1238 // refer to actual errors, we want to use the |destination_error_| as the | 1280 // refer to actual errors, we want to use the |destination_error_| as the |
1239 // argument to the Interrupt() routine, as it happened first. | 1281 // argument to the Interrupt() routine, as it happened first. |
1240 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) | 1282 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) |
1241 SetFullPath(full_path); | 1283 SetFullPath(full_path); |
1242 Interrupt(destination_error_); | 1284 Interrupt(destination_error_, UPDATE_OBSERVERS); |
1243 destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE; | 1285 destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE; |
1244 } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 1286 } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
1245 Interrupt(reason); | 1287 Interrupt(reason, UPDATE_OBSERVERS); |
1246 // All file errors result in file deletion above; no need to cleanup. The | 1288 // All file errors result in file deletion above; no need to cleanup. The |
1247 // current_path_ should be empty. Resuming this download will force a | 1289 // current_path_ should be empty. Resuming this download will force a |
1248 // restart and a re-doing of filename determination. | 1290 // restart and a re-doing of filename determination. |
1249 DCHECK(current_path_.empty()); | 1291 DCHECK(current_path_.empty()); |
1250 } else { | 1292 } else { |
1251 SetFullPath(full_path); | 1293 SetFullPath(full_path); |
1252 UpdateObservers(); | 1294 UpdateObservers(); |
1253 MaybeCompleteDownload(); | 1295 MaybeCompleteDownload(); |
1254 } | 1296 } |
1255 } | 1297 } |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1332 // will result in deleting the file on the file thread. So we don't | 1374 // will result in deleting the file on the file thread. So we don't |
1333 // care about the name having been changed. | 1375 // care about the name having been changed. |
1334 if (state_ != IN_PROGRESS_INTERNAL) | 1376 if (state_ != IN_PROGRESS_INTERNAL) |
1335 return; | 1377 return; |
1336 | 1378 |
1337 DVLOG(20) << __FUNCTION__ << "()" | 1379 DVLOG(20) << __FUNCTION__ << "()" |
1338 << " full_path = \"" << full_path.value() << "\"" | 1380 << " full_path = \"" << full_path.value() << "\"" |
1339 << " " << DebugString(false); | 1381 << " " << DebugString(false); |
1340 | 1382 |
1341 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 1383 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
1342 Interrupt(reason); | 1384 Interrupt(reason, UPDATE_OBSERVERS); |
1343 | 1385 |
1344 // All file errors should have resulted in in file deletion above. On | 1386 // All file errors should have resulted in in file deletion above. On |
1345 // resumption we will need to re-do filename determination. | 1387 // resumption we will need to re-do filename determination. |
1346 DCHECK(current_path_.empty()); | 1388 DCHECK(current_path_.empty()); |
1347 return; | 1389 return; |
1348 } | 1390 } |
1349 | 1391 |
1350 DCHECK(target_path_ == full_path); | 1392 DCHECK(target_path_ == full_path); |
1351 | 1393 |
1352 if (full_path != current_path_) { | 1394 if (full_path != current_path_) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1401 // we still need to set it auto-opened so that it can be removed from the | 1443 // we still need to set it auto-opened so that it can be removed from the |
1402 // download shelf. | 1444 // download shelf. |
1403 if (!IsTemporary()) | 1445 if (!IsTemporary()) |
1404 OpenDownload(); | 1446 OpenDownload(); |
1405 | 1447 |
1406 auto_opened_ = true; | 1448 auto_opened_ = true; |
1407 UpdateObservers(); | 1449 UpdateObservers(); |
1408 } | 1450 } |
1409 } | 1451 } |
1410 | 1452 |
1411 void DownloadItemImpl::OnResumeRequestStarted( | |
1412 DownloadItem* item, | |
1413 DownloadInterruptReason interrupt_reason) { | |
1414 // If |item| is not NULL, then Start() has been called already, and nothing | |
1415 // more needs to be done here. | |
1416 if (item) { | |
1417 DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); | |
1418 DCHECK_EQ(static_cast<DownloadItem*>(this), item); | |
1419 return; | |
1420 } | |
1421 // Otherwise, the request failed without passing through | |
1422 // DownloadResourceHandler::OnResponseStarted. | |
1423 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); | |
1424 Interrupt(interrupt_reason); | |
1425 } | |
1426 | |
1427 // **** End of Download progression cascade | 1453 // **** End of Download progression cascade |
1428 | 1454 |
1429 // An error occurred somewhere. | 1455 // An error occurred somewhere. |
1430 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { | 1456 void DownloadItemImpl::Interrupt( |
1457 DownloadInterruptReason reason, | |
1458 ShouldUpdateObservers should_update_observers) { | |
1431 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1459 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
1432 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason); | 1460 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason); |
1461 DVLOG(20) << __FUNCTION__ | |
1462 << "() reason=" << DownloadInterruptReasonToString(reason); | |
1433 | 1463 |
1434 // Somewhat counter-intuitively, it is possible for us to receive an | 1464 // Somewhat counter-intuitively, it is possible for us to receive an |
1435 // interrupt after we've already been interrupted. The generation of | 1465 // interrupt after we've already been interrupted. The generation of |
1436 // interrupts from the file thread Renames and the generation of | 1466 // interrupts from the file thread Renames and the generation of |
1437 // interrupts from disk writes go through two different mechanisms (driven | 1467 // interrupts from disk writes go through two different mechanisms (driven |
1438 // by rename requests from UI thread and by write requests from IO thread, | 1468 // by rename requests from UI thread and by write requests from IO thread, |
1439 // respectively), and since we choose not to keep state on the File thread, | 1469 // respectively), and since we choose not to keep state on the File thread, |
1440 // this is the place where the races collide. It's also possible for | 1470 // this is the place where the races collide. It's also possible for |
1441 // interrupts to race with cancels. | 1471 // interrupts to race with cancels. |
1442 | 1472 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1477 // from the DownloadFile, which would behave properly with setting | 1507 // from the DownloadFile, which would behave properly with setting |
1478 // all_data_saved_ to false here. | 1508 // all_data_saved_ to false here. |
1479 all_data_saved_ = false; | 1509 all_data_saved_ = false; |
1480 | 1510 |
1481 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS); | 1511 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS); |
1482 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); | 1512 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); |
1483 if (!GetWebContents()) | 1513 if (!GetWebContents()) |
1484 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS); | 1514 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS); |
1485 | 1515 |
1486 AutoResumeIfValid(); | 1516 AutoResumeIfValid(); |
1487 UpdateObservers(); | 1517 if (should_update_observers == UPDATE_OBSERVERS) |
1518 UpdateObservers(); | |
1488 } | 1519 } |
1489 | 1520 |
1490 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) { | 1521 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) { |
1491 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1522 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
1492 | 1523 |
1493 if (destroy_file) { | 1524 if (destroy_file) { |
1494 BrowserThread::PostTask( | 1525 BrowserThread::PostTask( |
1495 BrowserThread::FILE, FROM_HERE, | 1526 BrowserThread::FILE, FROM_HERE, |
1496 // Will be deleted at end of task execution. | 1527 // Will be deleted at end of task execution. |
1497 base::Bind(&DownloadFileCancel, base::Passed(&download_file_))); | 1528 base::Bind(&DownloadFileCancel, base::Passed(&download_file_))); |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1669 | 1700 |
1670 void DownloadItemImpl::ResumeInterruptedDownload() { | 1701 void DownloadItemImpl::ResumeInterruptedDownload() { |
1671 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1702 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
1672 if (!IsDownloadResumptionEnabled()) | 1703 if (!IsDownloadResumptionEnabled()) |
1673 return; | 1704 return; |
1674 | 1705 |
1675 // If we're not interrupted, ignore the request; our caller is drunk. | 1706 // If we're not interrupted, ignore the request; our caller is drunk. |
1676 if (state_ != INTERRUPTED_INTERNAL) | 1707 if (state_ != INTERRUPTED_INTERNAL) |
1677 return; | 1708 return; |
1678 | 1709 |
1710 // We are starting a new request. Shake off all pending operations. | |
1711 DCHECK(!download_file_); | |
1712 weak_ptr_factory_.InvalidateWeakPtrs(); | |
1713 | |
1714 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS); | |
1715 BrowserThread::PostTask( | |
1716 BrowserThread::UI, FROM_HERE, | |
1717 base::Bind(&DownloadItemImpl::InvokeDelegateForResumption, | |
1718 weak_ptr_factory_.GetWeakPtr())); | |
1719 } | |
1720 | |
1721 void DownloadItemImpl::InvokeDelegateForResumption() { | |
Randy Smith (Not in Mondays)
2016/02/05 00:51:41
Why replacing the sync invocation with an async in
asanka
2016/02/11 03:43:07
This CL relies on Start() never being called synch
| |
1722 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
1723 // A state change happend while we were out. This could be because of a | |
1724 // Cancel() call. Since we aren't resuming anymore, there's nothing else to | |
1725 // do. | |
1726 if (state_ != RESUMING_INTERNAL) | |
1727 return; | |
1728 | |
1679 // Reset the appropriate state if restarting. | 1729 // Reset the appropriate state if restarting. |
1680 ResumeMode mode = GetResumeMode(); | 1730 ResumeMode mode = GetResumeMode(); |
1681 if (mode == RESUME_MODE_IMMEDIATE_RESTART || | 1731 if (mode == RESUME_MODE_IMMEDIATE_RESTART || |
1682 mode == RESUME_MODE_USER_RESTART) { | 1732 mode == RESUME_MODE_USER_RESTART) { |
1683 received_bytes_ = 0; | 1733 received_bytes_ = 0; |
1684 hash_state_ = ""; | 1734 hash_state_ = ""; |
1685 last_modified_time_ = ""; | 1735 last_modified_time_ = ""; |
1686 etag_ = ""; | 1736 etag_ = ""; |
1687 } | 1737 } |
1688 | 1738 |
1689 scoped_ptr<DownloadUrlParameters> download_params; | 1739 scoped_ptr<DownloadUrlParameters> download_params; |
1690 if (GetWebContents()) { | 1740 if (GetWebContents()) { |
1691 download_params = | 1741 download_params = |
1692 DownloadUrlParameters::FromWebContents(GetWebContents(), GetURL()); | 1742 DownloadUrlParameters::FromWebContents(GetWebContents(), GetURL()); |
1693 } else { | 1743 } else { |
1694 download_params = make_scoped_ptr(new DownloadUrlParameters( | 1744 download_params = make_scoped_ptr(new DownloadUrlParameters( |
1695 GetURL(), -1, -1, -1, GetBrowserContext()->GetResourceContext())); | 1745 GetURL(), -1, -1, -1, GetBrowserContext()->GetResourceContext())); |
1696 } | 1746 } |
1697 | 1747 |
1698 download_params->set_file_path(GetFullPath()); | 1748 download_params->set_file_path(GetFullPath()); |
1699 download_params->set_offset(GetReceivedBytes()); | 1749 download_params->set_offset(GetReceivedBytes()); |
1700 download_params->set_hash_state(GetHashState()); | 1750 download_params->set_hash_state(GetHashState()); |
1701 download_params->set_last_modified(GetLastModifiedTime()); | 1751 download_params->set_last_modified(GetLastModifiedTime()); |
1702 download_params->set_etag(GetETag()); | 1752 download_params->set_etag(GetETag()); |
1703 download_params->set_callback( | |
1704 base::Bind(&DownloadItemImpl::OnResumeRequestStarted, | |
1705 weak_ptr_factory_.GetWeakPtr())); | |
1706 | 1753 |
1707 delegate_->ResumeInterruptedDownload(std::move(download_params), GetId()); | 1754 delegate_->ResumeInterruptedDownload(std::move(download_params), GetId()); |
1708 // Just in case we were interrupted while paused. | 1755 // Just in case we were interrupted while paused. |
1709 is_paused_ = false; | 1756 is_paused_ = false; |
1710 | |
1711 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS); | |
1712 } | 1757 } |
1713 | 1758 |
1714 // static | 1759 // static |
1715 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( | 1760 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( |
1716 DownloadInternalState internal_state) { | 1761 DownloadInternalState internal_state) { |
1717 switch (internal_state) { | 1762 switch (internal_state) { |
1718 case IN_PROGRESS_INTERNAL: | 1763 case IN_PROGRESS_INTERNAL: |
1719 return IN_PROGRESS; | 1764 return IN_PROGRESS; |
1720 case COMPLETING_INTERNAL: | 1765 case COMPLETING_INTERNAL: |
1721 return IN_PROGRESS; | 1766 return IN_PROGRESS; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1786 case RESUME_MODE_USER_CONTINUE: | 1831 case RESUME_MODE_USER_CONTINUE: |
1787 return "USER_CONTINUE"; | 1832 return "USER_CONTINUE"; |
1788 case RESUME_MODE_USER_RESTART: | 1833 case RESUME_MODE_USER_RESTART: |
1789 return "USER_RESTART"; | 1834 return "USER_RESTART"; |
1790 } | 1835 } |
1791 NOTREACHED() << "Unknown resume mode " << mode; | 1836 NOTREACHED() << "Unknown resume mode " << mode; |
1792 return "unknown"; | 1837 return "unknown"; |
1793 } | 1838 } |
1794 | 1839 |
1795 } // namespace content | 1840 } // namespace content |
OLD | NEW |