| 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, DelayedDownloadOpened, MaybeCompleteDownload, and | 7 // interfaces Start, DelayedDownloadOpened, MaybeCompleteDownload, and |
| 8 // OnDownloadCompleting are placed in chronological order with the other | 8 // OnDownloadCompleting are placed in chronological order with the other |
| 9 // (private) routines that together define a DownloadItem's state transitions | 9 // (private) routines 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 704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 // Somewhat counter-intuitively, it is possible for us to receive an | 819 // Somewhat counter-intuitively, it is possible for us to receive an |
| 822 // interrupt after we've already been interrupted. The generation of | 820 // interrupt after we've already been interrupted. The generation of |
| 823 // interrupts from the file thread Renames and the generation of | 821 // interrupts from the file thread Renames and the generation of |
| 824 // interrupts from disk writes go through two different mechanisms (driven | 822 // interrupts from disk writes go through two different mechanisms (driven |
| 825 // by rename requests from UI thread and by write requests from IO thread, | 823 // by rename requests from UI thread and by write requests from IO thread, |
| 826 // respectively), and since we choose not to keep state on the File thread, | 824 // respectively), and since we choose not to keep state on the File thread, |
| 827 // this is the place where the races collide. It's also possible for | 825 // this is the place where the races collide. It's also possible for |
| 828 // interrupts to race with cancels. | 826 // interrupts to race with cancels. |
| 829 | 827 |
| 830 // Whatever happens, the first one to hit the UI thread wins. | 828 // Whatever happens, the first one to hit the UI thread wins. |
| 831 if (state_ != IN_PROGRESS_INTERNAL && state_ != COMPLETING_INTERNAL) | 829 if (state_ != IN_PROGRESS_INTERNAL) |
| 832 return; | 830 return; |
| 833 | 831 |
| 834 last_reason_ = reason; | 832 last_reason_ = reason; |
| 835 TransitionTo(INTERRUPTED_INTERNAL); | 833 TransitionTo(INTERRUPTED_INTERNAL); |
| 836 | 834 |
| 837 CancelDownloadFile(); | 835 CancelDownloadFile(); |
| 838 | 836 |
| 839 // Cancel the originating URL request. | 837 // Cancel the originating URL request. |
| 840 request_handle_->CancelRequest(); | 838 request_handle_->CancelRequest(); |
| 841 | 839 |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 // spurious rename when we can just rename to the final | 1092 // spurious rename when we can just rename to the final |
| 1095 // filename. Unnecessary renames may cause bugs like | 1093 // filename. Unnecessary renames may cause bugs like |
| 1096 // http://crbug.com/74187. | 1094 // http://crbug.com/74187. |
| 1097 DCHECK(!is_save_package_download_); | 1095 DCHECK(!is_save_package_download_); |
| 1098 DCHECK(download_file_.get()); | 1096 DCHECK(download_file_.get()); |
| 1099 DownloadFile::RenameCompletionCallback callback = | 1097 DownloadFile::RenameCompletionCallback callback = |
| 1100 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, | 1098 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, |
| 1101 weak_ptr_factory_.GetWeakPtr()); | 1099 weak_ptr_factory_.GetWeakPtr()); |
| 1102 BrowserThread::PostTask( | 1100 BrowserThread::PostTask( |
| 1103 BrowserThread::FILE, FROM_HERE, | 1101 BrowserThread::FILE, FROM_HERE, |
| 1104 base::Bind(&DownloadFile::Rename, | 1102 base::Bind(&DownloadFile::RenameAndUniquify, |
| 1105 // Safe because we control download file lifetime. | 1103 // Safe because we control download file lifetime. |
| 1106 base::Unretained(download_file_.get()), | 1104 base::Unretained(download_file_.get()), |
| 1107 intermediate_path, false, callback)); | 1105 intermediate_path, callback)); |
| 1108 } | 1106 } |
| 1109 | 1107 |
| 1110 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( | 1108 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( |
| 1111 DownloadInterruptReason reason, | 1109 DownloadInterruptReason reason, |
| 1112 const FilePath& full_path) { | 1110 const FilePath& full_path) { |
| 1113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1114 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 1112 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
| 1115 Interrupt(reason); | 1113 Interrupt(reason); |
| 1116 } else { | 1114 } else { |
| 1117 SetFullPath(full_path); | 1115 SetFullPath(full_path); |
| 1118 UpdateObservers(); | 1116 UpdateObservers(); |
| 1119 } | 1117 } |
| 1120 | 1118 |
| 1121 delegate_->DownloadRenamedToIntermediateName(this); | 1119 delegate_->DownloadRenamedToIntermediateName(this); |
| 1122 } | 1120 } |
| 1123 | 1121 |
| 1124 // When SavePackage downloads MHTML to GData (see | 1122 // When SavePackage downloads MHTML to GData (see |
| 1125 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it | 1123 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it |
| 1126 // does for non-SavePackage downloads, but SavePackage downloads never satisfy | 1124 // does for non-SavePackage downloads, but SavePackage downloads never satisfy |
| 1127 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls | 1125 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls |
| 1128 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage | 1126 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage |
| 1129 // notices that the upload has completed and runs its normal Finish() pathway. | 1127 // notices that the upload has completed and runs its normal Finish() pathway. |
| 1130 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes | 1128 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes |
| 1131 // downloads. SavePackage always uses its own Finish() to mark downloads | 1129 // downloads. SavePackage always uses its own Finish() to mark downloads |
| 1132 // complete. | 1130 // complete. |
| 1133 void DownloadItemImpl::MaybeCompleteDownload() { | 1131 void DownloadItemImpl::MaybeCompleteDownload() { |
| 1134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1133 DCHECK(!is_save_package_download_); |
| 1135 | 1134 |
| 1136 if (!IsDownloadReadyForCompletion()) | 1135 if (!IsDownloadReadyForCompletion()) |
| 1137 return; | 1136 return; |
| 1138 | 1137 |
| 1139 // TODO(rdsmith): DCHECK that we only pass through this point | 1138 // TODO(rdsmith): DCHECK that we only pass through this point |
| 1140 // once per download. The natural way to do this is by a state | 1139 // once per download. The natural way to do this is by a state |
| 1141 // transition on the DownloadItem. | 1140 // transition on the DownloadItem. |
| 1142 | 1141 |
| 1143 // Confirm we're in the proper set of states to be here; | 1142 // Confirm we're in the proper set of states to be here; |
| 1144 // have all data, have a history handle, (validated or safe). | 1143 // have all data, have a history handle, (validated or safe). |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1164 delegate_->ReadyForDownloadCompletion( | 1163 delegate_->ReadyForDownloadCompletion( |
| 1165 this, base::Bind(&DownloadItemImpl::ReadyForDownloadCompletionDone, | 1164 this, base::Bind(&DownloadItemImpl::ReadyForDownloadCompletionDone, |
| 1166 weak_ptr_factory_.GetWeakPtr())); | 1165 weak_ptr_factory_.GetWeakPtr())); |
| 1167 } | 1166 } |
| 1168 | 1167 |
| 1169 void DownloadItemImpl::ReadyForDownloadCompletionDone() { | 1168 void DownloadItemImpl::ReadyForDownloadCompletionDone() { |
| 1170 if (state_ != IN_PROGRESS_INTERNAL) | 1169 if (state_ != IN_PROGRESS_INTERNAL) |
| 1171 return; | 1170 return; |
| 1172 | 1171 |
| 1173 VLOG(20) << __FUNCTION__ << "()" | 1172 VLOG(20) << __FUNCTION__ << "()" |
| 1174 << " needs rename = " << NeedsRename() | |
| 1175 << " " << DebugString(true); | 1173 << " " << DebugString(true); |
| 1176 DCHECK(!GetTargetFilePath().empty()); | 1174 DCHECK(!GetTargetFilePath().empty()); |
| 1177 DCHECK_NE(DANGEROUS, GetSafetyState()); | 1175 DCHECK_NE(DANGEROUS, GetSafetyState()); |
| 1178 | 1176 |
| 1179 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration. | 1177 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration. |
| 1180 if (is_save_package_download_) { | 1178 if (is_save_package_download_) { |
| 1181 // Avoid doing anything on the file thread; there's nothing we control | 1179 // Avoid doing anything on the file thread; there's nothing we control |
| 1182 // there. | 1180 // there. |
| 1183 OnDownloadFileReleased(DOWNLOAD_INTERRUPT_REASON_NONE); | 1181 // Strictly speaking, this skips giving the embedder a chance to open |
| 1182 // the download. But on a save package download, there's no real |
| 1183 // concept of opening. |
| 1184 Completed(); |
| 1184 return; | 1185 return; |
| 1185 } | 1186 } |
| 1186 | 1187 |
| 1187 DCHECK(download_file_.get()); | 1188 DCHECK(download_file_.get()); |
| 1188 if (NeedsRename()) { | 1189 // Unilaterally rename; even if it already has the right name, |
| 1189 DownloadFile::RenameCompletionCallback callback = | 1190 // we need theannotation. |
| 1190 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, | 1191 DownloadFile::RenameCompletionCallback callback = |
| 1191 weak_ptr_factory_.GetWeakPtr()); | 1192 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, |
| 1192 BrowserThread::PostTask( | 1193 weak_ptr_factory_.GetWeakPtr()); |
| 1193 BrowserThread::FILE, FROM_HERE, | 1194 BrowserThread::PostTask( |
| 1194 base::Bind(&DownloadFile::Rename, | 1195 BrowserThread::FILE, FROM_HERE, |
| 1195 base::Unretained(download_file_.get()), | 1196 base::Bind(&DownloadFile::RenameAndAnnotate, |
| 1196 GetTargetFilePath(), true, callback)); | 1197 base::Unretained(download_file_.get()), |
| 1197 } else { | 1198 GetTargetFilePath(), callback)); |
| 1198 ReleaseDownloadFile(); | |
| 1199 } | |
| 1200 } | 1199 } |
| 1201 | 1200 |
| 1202 void DownloadItemImpl::OnDownloadRenamedToFinalName( | 1201 void DownloadItemImpl::OnDownloadRenamedToFinalName( |
| 1203 DownloadInterruptReason reason, | 1202 DownloadInterruptReason reason, |
| 1204 const FilePath& full_path) { | 1203 const FilePath& full_path) { |
| 1205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1205 DCHECK(!is_save_package_download_); |
| 1206 | 1206 |
| 1207 // If a cancel or interrupt hit, we'll cancel the DownloadFile, which | 1207 // If a cancel or interrupt hit, we'll cancel the DownloadFile, which |
| 1208 // will result in deleting the file on the file thread. So we don't | 1208 // will result in deleting the file on the file thread. So we don't |
| 1209 // care about the name having been changed. | 1209 // care about the name having been changed. |
| 1210 if (state_ != IN_PROGRESS_INTERNAL) | 1210 if (state_ != IN_PROGRESS_INTERNAL) |
| 1211 return; | 1211 return; |
| 1212 | 1212 |
| 1213 VLOG(20) << __FUNCTION__ << "()" | 1213 VLOG(20) << __FUNCTION__ << "()" |
| 1214 << " full_path = \"" << full_path.value() << "\"" | 1214 << " full_path = \"" << full_path.value() << "\"" |
| 1215 << " needed rename = " << NeedsRename() | |
| 1216 << " " << DebugString(false); | 1215 << " " << DebugString(false); |
| 1217 DCHECK(NeedsRename()); | |
| 1218 | 1216 |
| 1219 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 1217 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
| 1220 Interrupt(reason); | 1218 Interrupt(reason); |
| 1221 return; | 1219 return; |
| 1222 } | 1220 } |
| 1223 | 1221 |
| 1224 // full_path is now the current and target file path. | 1222 DCHECK(target_path_ == full_path); |
| 1225 DCHECK(!full_path.empty()); | |
| 1226 target_path_ = full_path; | |
| 1227 SetFullPath(full_path); | |
| 1228 delegate_->DownloadRenamedToFinalName(this); | |
| 1229 | 1223 |
| 1230 ReleaseDownloadFile(); | 1224 if (full_path != current_path_) { |
| 1231 } | 1225 // full_path is now the current and target file path. |
| 1226 DCHECK(!full_path.empty()); |
| 1227 SetFullPath(full_path); |
| 1228 delegate_->DownloadRenamedToFinalName(this); |
| 1229 } |
| 1232 | 1230 |
| 1233 void DownloadItemImpl::ReleaseDownloadFile() { | |
| 1234 // Complete the download and release the DownloadFile. | 1231 // Complete the download and release the DownloadFile. |
| 1235 DCHECK(!is_save_package_download_); | |
| 1236 DCHECK(download_file_.get()); | 1232 DCHECK(download_file_.get()); |
| 1237 BrowserThread::PostTask( | 1233 BrowserThread::PostTask( |
| 1238 BrowserThread::FILE, FROM_HERE, | 1234 BrowserThread::FILE, FROM_HERE, |
| 1239 base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass()), | 1235 base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass()))); |
| 1240 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | |
| 1241 weak_ptr_factory_.GetWeakPtr()))); | |
| 1242 | 1236 |
| 1243 // We're not completely done with the download item yet, but at this | 1237 // We're not completely done with the download item yet, but at this |
| 1244 // point we're committed to complete the download. Cancels (or Interrupts, | 1238 // point we're committed to complete the download. Cancels (or Interrupts, |
| 1245 // though it's not clear how they could happen) after this point will be | 1239 // though it's not clear how they could happen) after this point will be |
| 1246 // ignored. | 1240 // ignored. |
| 1247 TransitionTo(COMPLETING_INTERNAL); | 1241 TransitionTo(COMPLETING_INTERNAL); |
| 1248 } | |
| 1249 | 1242 |
| 1250 void DownloadItemImpl::OnDownloadFileReleased(DownloadInterruptReason reason) { | |
| 1251 if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | |
| 1252 Interrupt(reason); | |
| 1253 return; | |
| 1254 } | |
| 1255 if (delegate_->ShouldOpenDownload(this)) | 1243 if (delegate_->ShouldOpenDownload(this)) |
| 1256 Completed(); | 1244 Completed(); |
| 1257 else | 1245 else |
| 1258 delegate_delayed_complete_ = true; | 1246 delegate_delayed_complete_ = true; |
| 1259 } | 1247 } |
| 1260 | 1248 |
| 1261 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { | 1249 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { |
| 1262 auto_opened_ = auto_opened; | 1250 auto_opened_ = auto_opened; |
| 1263 Completed(); | 1251 Completed(); |
| 1264 } | 1252 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1323 | 1311 |
| 1324 // If the download hasn't been inserted into the history system | 1312 // If the download hasn't been inserted into the history system |
| 1325 // (which occurs strictly after file name determination, intermediate | 1313 // (which occurs strictly after file name determination, intermediate |
| 1326 // file rename, and UI display) then it's not ready for completion. | 1314 // file rename, and UI display) then it's not ready for completion. |
| 1327 if (!IsPersisted()) | 1315 if (!IsPersisted()) |
| 1328 return false; | 1316 return false; |
| 1329 | 1317 |
| 1330 return true; | 1318 return true; |
| 1331 } | 1319 } |
| 1332 | 1320 |
| 1333 bool DownloadItemImpl::NeedsRename() const { | |
| 1334 DCHECK(target_path_.DirName() == current_path_.DirName()); | |
| 1335 return target_path_ != current_path_; | |
| 1336 } | |
| 1337 | |
| 1338 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { | 1321 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { |
| 1339 if (state_ == new_state) | 1322 if (state_ == new_state) |
| 1340 return; | 1323 return; |
| 1341 | 1324 |
| 1342 DownloadInternalState old_state = state_; | 1325 DownloadInternalState old_state = state_; |
| 1343 state_ = new_state; | 1326 state_ = new_state; |
| 1344 | 1327 |
| 1345 switch (state_) { | 1328 switch (state_) { |
| 1346 case COMPLETING_INTERNAL: | 1329 case COMPLETING_INTERNAL: |
| 1347 bound_net_log_.AddEvent( | 1330 bound_net_log_.AddEvent( |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1463 return "CANCELLED"; | 1446 return "CANCELLED"; |
| 1464 case INTERRUPTED_INTERNAL: | 1447 case INTERRUPTED_INTERNAL: |
| 1465 return "INTERRUPTED"; | 1448 return "INTERRUPTED"; |
| 1466 default: | 1449 default: |
| 1467 NOTREACHED() << "Unknown download state " << state; | 1450 NOTREACHED() << "Unknown download state " << state; |
| 1468 return "unknown"; | 1451 return "unknown"; |
| 1469 }; | 1452 }; |
| 1470 } | 1453 } |
| 1471 | 1454 |
| 1472 } // namespace content | 1455 } // namespace content |
| OLD | NEW |