| 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 // interfaces Start, MaybeCompleteDownload, and OnDownloadCompleting | 7 // interfaces Start, MaybeCompleteDownload, and OnDownloadCompleting |
| 8 // are placed in chronological order with the other (private) routines | 8 // are placed in chronological order with the other (private) routines |
| 9 // that together define a DownloadItem's state transitions | 9 // that together define a DownloadItem's state transitions |
| 10 // as the download progresses. See "Download progression cascade" later in | 10 // as the download progresses. See "Download progression cascade" later in |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 virtual void ResumeRequest() const OVERRIDE {} | 92 virtual void ResumeRequest() const OVERRIDE {} |
| 93 virtual void CancelRequest() const OVERRIDE {} | 93 virtual void CancelRequest() const OVERRIDE {} |
| 94 virtual std::string DebugString() const OVERRIDE { | 94 virtual std::string DebugString() const OVERRIDE { |
| 95 return "Null DownloadRequestHandle"; | 95 return "Null DownloadRequestHandle"; |
| 96 } | 96 } |
| 97 }; | 97 }; |
| 98 | 98 |
| 99 // Wrapper around DownloadFile::Detach and DownloadFile::Cancel that | 99 // Wrapper around DownloadFile::Detach and DownloadFile::Cancel that |
| 100 // takes ownership of the DownloadFile and hence implicitly destroys it | 100 // takes ownership of the DownloadFile and hence implicitly destroys it |
| 101 // at the end of the function. | 101 // at the end of the function. |
| 102 static void DownloadFileDetach( | 102 static void DownloadFileDetach(scoped_ptr<DownloadFile> download_file) { |
| 103 scoped_ptr<DownloadFile> download_file, | |
| 104 const DownloadFile::DetachCompletionCallback& callback) { | |
| 105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 106 download_file->Detach(callback); | 104 download_file->Detach(); |
| 107 } | 105 } |
| 108 | 106 |
| 109 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) { | 107 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) { |
| 110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 111 download_file->Cancel(); | 109 download_file->Cancel(); |
| 112 } | 110 } |
| 113 | 111 |
| 114 } // namespace | 112 } // namespace |
| 115 | 113 |
| 116 // Our download table ID starts at 1, so we use 0 to represent a download that | 114 // Our download table ID starts at 1, so we use 0 to represent a download that |
| (...skipping 950 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1067 // spurious rename when we can just rename to the final | 1065 // spurious rename when we can just rename to the final |
| 1068 // filename. Unnecessary renames may cause bugs like | 1066 // filename. Unnecessary renames may cause bugs like |
| 1069 // http://crbug.com/74187. | 1067 // http://crbug.com/74187. |
| 1070 DCHECK(!is_save_package_download_); | 1068 DCHECK(!is_save_package_download_); |
| 1071 DCHECK(download_file_.get()); | 1069 DCHECK(download_file_.get()); |
| 1072 DownloadFile::RenameCompletionCallback callback = | 1070 DownloadFile::RenameCompletionCallback callback = |
| 1073 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, | 1071 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, |
| 1074 weak_ptr_factory_.GetWeakPtr()); | 1072 weak_ptr_factory_.GetWeakPtr()); |
| 1075 BrowserThread::PostTask( | 1073 BrowserThread::PostTask( |
| 1076 BrowserThread::FILE, FROM_HERE, | 1074 BrowserThread::FILE, FROM_HERE, |
| 1077 base::Bind(&DownloadFile::Rename, | 1075 base::Bind(&DownloadFile::RenameAndUniquify, |
| 1078 // Safe because we control download file lifetime. | 1076 // Safe because we control download file lifetime. |
| 1079 base::Unretained(download_file_.get()), | 1077 base::Unretained(download_file_.get()), |
| 1080 intermediate_path, false, callback)); | 1078 intermediate_path, callback)); |
| 1081 } | 1079 } |
| 1082 | 1080 |
| 1083 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( | 1081 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( |
| 1084 DownloadInterruptReason reason, | 1082 DownloadInterruptReason reason, |
| 1085 const FilePath& full_path) { | 1083 const FilePath& full_path) { |
| 1086 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1084 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1087 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 1085 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
| 1088 Interrupt(reason); | 1086 Interrupt(reason); |
| 1089 } else { | 1087 } else { |
| 1090 SetFullPath(full_path); | 1088 SetFullPath(full_path); |
| 1091 UpdateObservers(); | 1089 UpdateObservers(); |
| 1092 } | 1090 } |
| 1093 | 1091 |
| 1094 delegate_->DownloadRenamedToIntermediateName(this); | 1092 delegate_->DownloadRenamedToIntermediateName(this); |
| 1095 } | 1093 } |
| 1096 | 1094 |
| 1097 // When SavePackage downloads MHTML to GData (see | 1095 // When SavePackage downloads MHTML to GData (see |
| 1098 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it | 1096 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it |
| 1099 // does for non-SavePackage downloads, but SavePackage downloads never satisfy | 1097 // does for non-SavePackage downloads, but SavePackage downloads never satisfy |
| 1100 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls | 1098 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls |
| 1101 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage | 1099 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage |
| 1102 // notices that the upload has completed and runs its normal Finish() pathway. | 1100 // notices that the upload has completed and runs its normal Finish() pathway. |
| 1103 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes | 1101 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes |
| 1104 // downloads. SavePackage always uses its own Finish() to mark downloads | 1102 // downloads. SavePackage always uses its own Finish() to mark downloads |
| 1105 // complete. | 1103 // complete. |
| 1106 void DownloadItemImpl::MaybeCompleteDownload() { | 1104 void DownloadItemImpl::MaybeCompleteDownload() { |
| 1107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1106 DCHECK(!is_save_package_download_); |
| 1108 | 1107 |
| 1109 if (!IsDownloadReadyForCompletion()) | 1108 if (!IsDownloadReadyForCompletion()) |
| 1110 return; | 1109 return; |
| 1111 | 1110 |
| 1112 // TODO(rdsmith): DCHECK that we only pass through this point | 1111 // TODO(rdsmith): DCHECK that we only pass through this point |
| 1113 // once per download. The natural way to do this is by a state | 1112 // once per download. The natural way to do this is by a state |
| 1114 // transition on the DownloadItem. | 1113 // transition on the DownloadItem. |
| 1115 | 1114 |
| 1116 // Confirm we're in the proper set of states to be here; | 1115 // Confirm we're in the proper set of states to be here; |
| 1117 // have all data, have a history handle, (validated or safe). | 1116 // have all data, have a history handle, (validated or safe). |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1137 delegate_->ReadyForDownloadCompletion( | 1136 delegate_->ReadyForDownloadCompletion( |
| 1138 this, base::Bind(&DownloadItemImpl::ReadyForDownloadCompletionDone, | 1137 this, base::Bind(&DownloadItemImpl::ReadyForDownloadCompletionDone, |
| 1139 weak_ptr_factory_.GetWeakPtr())); | 1138 weak_ptr_factory_.GetWeakPtr())); |
| 1140 } | 1139 } |
| 1141 | 1140 |
| 1142 void DownloadItemImpl::ReadyForDownloadCompletionDone() { | 1141 void DownloadItemImpl::ReadyForDownloadCompletionDone() { |
| 1143 if (state_ != IN_PROGRESS_INTERNAL) | 1142 if (state_ != IN_PROGRESS_INTERNAL) |
| 1144 return; | 1143 return; |
| 1145 | 1144 |
| 1146 VLOG(20) << __FUNCTION__ << "()" | 1145 VLOG(20) << __FUNCTION__ << "()" |
| 1147 << " needs rename = " << NeedsRename() | |
| 1148 << " " << DebugString(true); | 1146 << " " << DebugString(true); |
| 1149 DCHECK(!GetTargetFilePath().empty()); | 1147 DCHECK(!GetTargetFilePath().empty()); |
| 1150 DCHECK_NE(DANGEROUS, GetSafetyState()); | 1148 DCHECK_NE(DANGEROUS, GetSafetyState()); |
| 1151 | 1149 |
| 1152 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration. | 1150 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration. |
| 1153 if (is_save_package_download_) { | 1151 if (is_save_package_download_) { |
| 1154 // Avoid doing anything on the file thread; there's nothing we control | 1152 // Avoid doing anything on the file thread; there's nothing we control |
| 1155 // there. | 1153 // there. |
| 1156 OnDownloadFileReleased(DOWNLOAD_INTERRUPT_REASON_NONE); | 1154 // Strictly speaking, this skips giving the embedder a chance to open |
| 1155 // the download. But on a save package download, there's no real |
| 1156 // concept of opening. |
| 1157 Completed(); |
| 1157 return; | 1158 return; |
| 1158 } | 1159 } |
| 1159 | 1160 |
| 1160 DCHECK(download_file_.get()); | 1161 DCHECK(download_file_.get()); |
| 1161 if (NeedsRename()) { | 1162 // Unilaterally rename; even if it already has the right name, |
| 1162 DownloadFile::RenameCompletionCallback callback = | 1163 // we need theannotation. |
| 1163 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, | 1164 DownloadFile::RenameCompletionCallback callback = |
| 1164 weak_ptr_factory_.GetWeakPtr()); | 1165 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, |
| 1165 BrowserThread::PostTask( | 1166 weak_ptr_factory_.GetWeakPtr()); |
| 1166 BrowserThread::FILE, FROM_HERE, | 1167 BrowserThread::PostTask( |
| 1167 base::Bind(&DownloadFile::Rename, | 1168 BrowserThread::FILE, FROM_HERE, |
| 1168 base::Unretained(download_file_.get()), | 1169 base::Bind(&DownloadFile::RenameAndAnnotate, |
| 1169 GetTargetFilePath(), true, callback)); | 1170 base::Unretained(download_file_.get()), |
| 1170 } else { | 1171 GetTargetFilePath(), callback)); |
| 1171 ReleaseDownloadFile(); | |
| 1172 } | |
| 1173 } | 1172 } |
| 1174 | 1173 |
| 1175 void DownloadItemImpl::OnDownloadRenamedToFinalName( | 1174 void DownloadItemImpl::OnDownloadRenamedToFinalName( |
| 1176 DownloadInterruptReason reason, | 1175 DownloadInterruptReason reason, |
| 1177 const FilePath& full_path) { | 1176 const FilePath& full_path) { |
| 1178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1178 DCHECK(!is_save_package_download_); |
| 1179 | 1179 |
| 1180 // If a cancel or interrupt hit, we'll cancel the DownloadFile, which | 1180 // If a cancel or interrupt hit, we'll cancel the DownloadFile, which |
| 1181 // will result in deleting the file on the file thread. So we don't | 1181 // will result in deleting the file on the file thread. So we don't |
| 1182 // care about the name having been changed. | 1182 // care about the name having been changed. |
| 1183 if (state_ != IN_PROGRESS_INTERNAL) | 1183 if (state_ != IN_PROGRESS_INTERNAL) |
| 1184 return; | 1184 return; |
| 1185 | 1185 |
| 1186 VLOG(20) << __FUNCTION__ << "()" | 1186 VLOG(20) << __FUNCTION__ << "()" |
| 1187 << " full_path = \"" << full_path.value() << "\"" | 1187 << " full_path = \"" << full_path.value() << "\"" |
| 1188 << " needed rename = " << NeedsRename() | |
| 1189 << " " << DebugString(false); | 1188 << " " << DebugString(false); |
| 1190 DCHECK(NeedsRename()); | |
| 1191 | 1189 |
| 1192 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 1190 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
| 1193 Interrupt(reason); | 1191 Interrupt(reason); |
| 1194 return; | 1192 return; |
| 1195 } | 1193 } |
| 1196 | 1194 |
| 1197 // full_path is now the current and target file path. | 1195 DCHECK(target_path_ == full_path); |
| 1198 DCHECK(!full_path.empty()); | |
| 1199 target_path_ = full_path; | |
| 1200 SetFullPath(full_path); | |
| 1201 delegate_->DownloadRenamedToFinalName(this); | |
| 1202 | 1196 |
| 1203 ReleaseDownloadFile(); | 1197 if (full_path != current_path_) { |
| 1204 } | 1198 // full_path is now the current and target file path. |
| 1199 DCHECK(!full_path.empty()); |
| 1200 SetFullPath(full_path); |
| 1201 delegate_->DownloadRenamedToFinalName(this); |
| 1202 } |
| 1205 | 1203 |
| 1206 void DownloadItemImpl::ReleaseDownloadFile() { | |
| 1207 // Complete the download and release the DownloadFile. | 1204 // Complete the download and release the DownloadFile. |
| 1208 DCHECK(!is_save_package_download_); | |
| 1209 DCHECK(download_file_.get()); | 1205 DCHECK(download_file_.get()); |
| 1210 BrowserThread::PostTask( | 1206 BrowserThread::PostTask( |
| 1211 BrowserThread::FILE, FROM_HERE, | 1207 BrowserThread::FILE, FROM_HERE, |
| 1212 base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass()), | 1208 base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass()))); |
| 1213 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | |
| 1214 weak_ptr_factory_.GetWeakPtr()))); | |
| 1215 | 1209 |
| 1216 // We're not completely done with the download item yet, but at this | 1210 // We're not completely done with the download item yet, but at this |
| 1217 // point we're committed to complete the download. Cancels (or Interrupts, | 1211 // point we're committed to complete the download. Cancels (or Interrupts, |
| 1218 // though it's not clear how they could happen) after this point will be | 1212 // though it's not clear how they could happen) after this point will be |
| 1219 // ignored. | 1213 // ignored. |
| 1220 TransitionTo(COMPLETING_INTERNAL); | 1214 TransitionTo(COMPLETING_INTERNAL); |
| 1221 } | |
| 1222 | 1215 |
| 1223 void DownloadItemImpl::OnDownloadFileReleased(DownloadInterruptReason reason) { | |
| 1224 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | |
| 1225 Interrupt(reason); | |
| 1226 return; | |
| 1227 } | |
| 1228 if (delegate_->ShouldOpenDownload( | 1216 if (delegate_->ShouldOpenDownload( |
| 1229 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened, | 1217 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened, |
| 1230 weak_ptr_factory_.GetWeakPtr()))) { | 1218 weak_ptr_factory_.GetWeakPtr()))) { |
| 1231 Completed(); | 1219 Completed(); |
| 1232 } else { | 1220 } else { |
| 1233 delegate_delayed_complete_ = true; | 1221 delegate_delayed_complete_ = true; |
| 1234 } | 1222 } |
| 1235 } | 1223 } |
| 1236 | 1224 |
| 1237 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { | 1225 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1273 // Somewhat counter-intuitively, it is possible for us to receive an | 1261 // Somewhat counter-intuitively, it is possible for us to receive an |
| 1274 // interrupt after we've already been interrupted. The generation of | 1262 // interrupt after we've already been interrupted. The generation of |
| 1275 // interrupts from the file thread Renames and the generation of | 1263 // interrupts from the file thread Renames and the generation of |
| 1276 // interrupts from disk writes go through two different mechanisms (driven | 1264 // interrupts from disk writes go through two different mechanisms (driven |
| 1277 // by rename requests from UI thread and by write requests from IO thread, | 1265 // by rename requests from UI thread and by write requests from IO thread, |
| 1278 // respectively), and since we choose not to keep state on the File thread, | 1266 // respectively), and since we choose not to keep state on the File thread, |
| 1279 // this is the place where the races collide. It's also possible for | 1267 // this is the place where the races collide. It's also possible for |
| 1280 // interrupts to race with cancels. | 1268 // interrupts to race with cancels. |
| 1281 | 1269 |
| 1282 // Whatever happens, the first one to hit the UI thread wins. | 1270 // Whatever happens, the first one to hit the UI thread wins. |
| 1283 if (state_ != IN_PROGRESS_INTERNAL && state_ != COMPLETING_INTERNAL) | 1271 if (state_ != IN_PROGRESS_INTERNAL) |
| 1284 return; | 1272 return; |
| 1285 | 1273 |
| 1286 last_reason_ = reason; | 1274 last_reason_ = reason; |
| 1287 TransitionTo(INTERRUPTED_INTERNAL); | 1275 TransitionTo(INTERRUPTED_INTERNAL); |
| 1288 | 1276 |
| 1289 CancelDownloadFile(); | 1277 CancelDownloadFile(); |
| 1290 | 1278 |
| 1291 // Cancel the originating URL request. | 1279 // Cancel the originating URL request. |
| 1292 request_handle_->CancelRequest(); | 1280 request_handle_->CancelRequest(); |
| 1293 | 1281 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1326 | 1314 |
| 1327 // If the download hasn't been inserted into the history system | 1315 // If the download hasn't been inserted into the history system |
| 1328 // (which occurs strictly after file name determination, intermediate | 1316 // (which occurs strictly after file name determination, intermediate |
| 1329 // file rename, and UI display) then it's not ready for completion. | 1317 // file rename, and UI display) then it's not ready for completion. |
| 1330 if (!IsPersisted()) | 1318 if (!IsPersisted()) |
| 1331 return false; | 1319 return false; |
| 1332 | 1320 |
| 1333 return true; | 1321 return true; |
| 1334 } | 1322 } |
| 1335 | 1323 |
| 1336 bool DownloadItemImpl::NeedsRename() const { | |
| 1337 DCHECK(target_path_.DirName() == current_path_.DirName()); | |
| 1338 return target_path_ != current_path_; | |
| 1339 } | |
| 1340 | |
| 1341 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { | 1324 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { |
| 1342 if (state_ == new_state) | 1325 if (state_ == new_state) |
| 1343 return; | 1326 return; |
| 1344 | 1327 |
| 1345 DownloadInternalState old_state = state_; | 1328 DownloadInternalState old_state = state_; |
| 1346 state_ = new_state; | 1329 state_ = new_state; |
| 1347 | 1330 |
| 1348 switch (state_) { | 1331 switch (state_) { |
| 1349 case COMPLETING_INTERNAL: | 1332 case COMPLETING_INTERNAL: |
| 1350 bound_net_log_.AddEvent( | 1333 bound_net_log_.AddEvent( |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1466 return "CANCELLED"; | 1449 return "CANCELLED"; |
| 1467 case INTERRUPTED_INTERNAL: | 1450 case INTERRUPTED_INTERNAL: |
| 1468 return "INTERRUPTED"; | 1451 return "INTERRUPTED"; |
| 1469 default: | 1452 default: |
| 1470 NOTREACHED() << "Unknown download state " << state; | 1453 NOTREACHED() << "Unknown download state " << state; |
| 1471 return "unknown"; | 1454 return "unknown"; |
| 1472 }; | 1455 }; |
| 1473 } | 1456 } |
| 1474 | 1457 |
| 1475 } // namespace content | 1458 } // namespace content |
| OLD | NEW |