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

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

Issue 11366121: Split DownloadFile::Rename into RenameAndUniquify and RenameAndAnnotate. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Incorporated comments. Created 8 years, 1 month 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 // 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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698