Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(517)

Side by Side Diff: content/browser/download/download_item_impl.cc

Issue 148133007: [Downloads] Always call DM::StartDownload() for explicit downloads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698