Chromium Code Reviews| 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 |