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

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

Issue 7646025: Detect file system errors during downloads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed comment. Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #include "content/browser/download/download_file_manager.h" 5 #include "content/browser/download/download_file_manager.h"
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "base/task.h" 10 #include "base/task.h"
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 // DownloadFile has been deleted. 161 // DownloadFile has been deleted.
162 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { 162 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) {
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
164 std::vector<DownloadBuffer::Contents> contents; 164 std::vector<DownloadBuffer::Contents> contents;
165 { 165 {
166 base::AutoLock auto_lock(buffer->lock); 166 base::AutoLock auto_lock(buffer->lock);
167 contents.swap(buffer->contents); 167 contents.swap(buffer->contents);
168 } 168 }
169 169
170 DownloadFile* download_file = GetDownloadFile(id); 170 DownloadFile* download_file = GetDownloadFile(id);
171 bool had_error = false;
171 for (size_t i = 0; i < contents.size(); ++i) { 172 for (size_t i = 0; i < contents.size(); ++i) {
172 net::IOBuffer* data = contents[i].first; 173 net::IOBuffer* data = contents[i].first;
173 const int data_len = contents[i].second; 174 const int data_len = contents[i].second;
174 if (download_file) 175 if (!had_error && download_file) {
175 download_file->AppendDataToFile(data->data(), data_len); 176 bool write_succeeded =
177 download_file->AppendDataToFile(data->data(), data_len);
178 if (!write_succeeded) {
179 // Write failed: interrupt the download.
180 DownloadManager* download_manager = download_file->GetDownloadManager();
181 had_error = true;
182
183 int64 bytes_downloaded = download_file->bytes_so_far();
184 // Calling this here in case we get more data, to avoid
185 // processing data after an error. That could lead to
186 // files that are corrupted if the later processing succeeded.
187 CancelDownload(id);
188 download_file = NULL; // Was deleted in |CancelDownload|.
189
190 if (download_manager) {
191 BrowserThread::PostTask(
192 BrowserThread::UI,
193 FROM_HERE,
194 NewRunnableMethod(
195 download_manager,
196 &DownloadManager::OnDownloadError,
197 id,
198 bytes_downloaded,
199 net::ERR_FAILED));
200 }
201 }
202 }
176 data->Release(); 203 data->Release();
177 } 204 }
178 } 205 }
179 206
180 void DownloadFileManager::OnResponseCompleted( 207 void DownloadFileManager::OnResponseCompleted(
181 int id, 208 int id,
182 DownloadBuffer* buffer, 209 DownloadBuffer* buffer,
183 int os_error, 210 int net_error,
184 const std::string& security_info) { 211 const std::string& security_info) {
185 VLOG(20) << __FUNCTION__ << "()" << " id = " << id 212 VLOG(20) << __FUNCTION__ << "()" << " id = " << id
186 << " os_error = " << os_error 213 << " net_error = " << net_error
187 << " security_info = \"" << security_info << "\""; 214 << " security_info = \"" << security_info << "\"";
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
189 delete buffer; 216 delete buffer;
190 DownloadFile* download_file = GetDownloadFile(id); 217 DownloadFile* download_file = GetDownloadFile(id);
191 if (!download_file) 218 if (!download_file)
192 return; 219 return;
193 220
194 download_file->Finish(); 221 download_file->Finish();
195 222
196 DownloadManager* download_manager = download_file->GetDownloadManager(); 223 DownloadManager* download_manager = download_file->GetDownloadManager();
197 if (!download_manager) { 224 if (!download_manager) {
198 CancelDownload(id); 225 CancelDownload(id);
199 return; 226 return;
200 } 227 }
201 228
202 std::string hash; 229 std::string hash;
203 if (!download_file->GetSha256Hash(&hash)) 230 if (!download_file->GetSha256Hash(&hash))
204 hash.clear(); 231 hash.clear();
205 232
206 BrowserThread::PostTask( 233 // ERR_CONNECTION_CLOSED is allowed since a number of servers in the wild
207 BrowserThread::UI, FROM_HERE, 234 // advertise a larger Content-Length than the amount of bytes in the message
208 NewRunnableMethod( 235 // body, and then close the connection. Other browsers - IE8, Firefox 4.0.1,
209 download_manager, &DownloadManager::OnResponseCompleted, 236 // and Safari 5.0.4 - treat the download as complete in this case, so we
210 id, download_file->bytes_so_far(), os_error, hash)); 237 // follow their lead.
238 if (net_error == net::OK || net_error == net::ERR_CONNECTION_CLOSED) {
239 BrowserThread::PostTask(
240 BrowserThread::UI,
241 FROM_HERE,
242 NewRunnableMethod(
243 download_manager,
244 &DownloadManager::OnResponseCompleted,
245 id,
246 download_file->bytes_so_far(),
247 hash));
248 } else {
249 BrowserThread::PostTask(
250 BrowserThread::UI,
251 FROM_HERE,
252 NewRunnableMethod(
253 download_manager,
254 &DownloadManager::OnDownloadError,
255 id,
256 download_file->bytes_so_far(),
257 net_error));
258 }
211 // We need to keep the download around until the UI thread has finalized 259 // We need to keep the download around until the UI thread has finalized
212 // the name. 260 // the name.
213 } 261 }
214 262
215 // This method will be sent via a user action, or shutdown on the UI thread, and 263 // This method will be sent via a user action, or shutdown on the UI thread, and
216 // run on the download thread. Since this message has been sent from the UI 264 // run on the download thread. Since this message has been sent from the UI
217 // thread, the download may have already completed and won't exist in our map. 265 // thread, the download may have already completed and won't exist in our map.
218 void DownloadFileManager::CancelDownload(int id) { 266 void DownloadFileManager::CancelDownload(int id) {
219 VLOG(20) << __FUNCTION__ << "()" << " id = " << id; 267 VLOG(20) << __FUNCTION__ << "()" << " id = " << id;
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 DownloadFile* download_file = GetDownloadFile(id); 334 DownloadFile* download_file = GetDownloadFile(id);
287 if (!download_file) 335 if (!download_file)
288 return; 336 return;
289 337
290 VLOG(20) << __FUNCTION__ << "()" 338 VLOG(20) << __FUNCTION__ << "()"
291 << " download_file = " << download_file->DebugString(); 339 << " download_file = " << download_file->DebugString();
292 340
293 if (!download_file->Rename(full_path)) { 341 if (!download_file->Rename(full_path)) {
294 // Error. Between the time the UI thread generated 'full_path' to the time 342 // Error. Between the time the UI thread generated 'full_path' to the time
295 // this code runs, something happened that prevents us from renaming. 343 // this code runs, something happened that prevents us from renaming.
296 CancelDownloadOnRename(id); 344 CancelDownloadOnRename(id, net::ERR_FAILED);
297 } 345 }
298 } 346 }
299 347
300 // The DownloadManager in the UI thread has provided a final name for the 348 // The DownloadManager in the UI thread has provided a final name for the
301 // download specified by 'id'. Rename the download that's in the process 349 // download specified by 'id'. Rename the download that's in the process
302 // of completing. 350 // of completing.
303 // 351 //
304 // There are 2 possible rename cases where this method can be called: 352 // There are 2 possible rename cases where this method can be called:
305 // 1. foo.crdownload -> foo (final, safe) 353 // 1. foo.crdownload -> foo (final, safe)
306 // 2. Unconfirmed.xxx.crdownload -> xxx (final, validated) 354 // 2. Unconfirmed.xxx.crdownload -> xxx (final, validated)
(...skipping 27 matching lines...) Expand all
334 uniquifier = download_util::GetUniquePathNumber(new_path); 382 uniquifier = download_util::GetUniquePathNumber(new_path);
335 if (uniquifier > 0) { 383 if (uniquifier > 0) {
336 download_util::AppendNumberToPath(&new_path, uniquifier); 384 download_util::AppendNumberToPath(&new_path, uniquifier);
337 } 385 }
338 } 386 }
339 387
340 // Rename the file, overwriting if necessary. 388 // Rename the file, overwriting if necessary.
341 if (!download_file->Rename(new_path)) { 389 if (!download_file->Rename(new_path)) {
342 // Error. Between the time the UI thread generated 'full_path' to the time 390 // Error. Between the time the UI thread generated 'full_path' to the time
343 // this code runs, something happened that prevents us from renaming. 391 // this code runs, something happened that prevents us from renaming.
344 CancelDownloadOnRename(id); 392 CancelDownloadOnRename(id, net::ERR_FAILED);
345 return; 393 return;
346 } 394 }
347 395
348 #if defined(OS_MACOSX) 396 #if defined(OS_MACOSX)
349 // Done here because we only want to do this once; see 397 // Done here because we only want to do this once; see
350 // http://crbug.com/13120 for details. 398 // http://crbug.com/13120 for details.
351 download_file->AnnotateWithSourceInformation(); 399 download_file->AnnotateWithSourceInformation();
352 #endif 400 #endif
353 401
354 BrowserThread::PostTask( 402 BrowserThread::PostTask(
355 BrowserThread::UI, FROM_HERE, 403 BrowserThread::UI, FROM_HERE,
356 NewRunnableMethod( 404 NewRunnableMethod(
357 download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id, 405 download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id,
358 new_path, uniquifier)); 406 new_path, uniquifier));
359 } 407 }
360 408
361 // Called only from RenameInProgressDownloadFile and 409 // Called only from RenameInProgressDownloadFile and
362 // RenameCompletingDownloadFile on the FILE thread. 410 // RenameCompletingDownloadFile on the FILE thread.
363 void DownloadFileManager::CancelDownloadOnRename(int id) { 411 void DownloadFileManager::CancelDownloadOnRename(int id, int rename_error) {
364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
365 413
366 DownloadFile* download_file = GetDownloadFile(id); 414 DownloadFile* download_file = GetDownloadFile(id);
367 if (!download_file) 415 if (!download_file)
368 return; 416 return;
369 417
370 DownloadManager* download_manager = download_file->GetDownloadManager(); 418 DownloadManager* download_manager = download_file->GetDownloadManager();
371 if (!download_manager) { 419 if (!download_manager) {
372 // Without a download manager, we can't cancel the request normally, so we 420 // Without a download manager, we can't cancel the request normally, so we
373 // need to do it here. The normal path will also update the download 421 // need to do it here. The normal path will also update the download
374 // history before cancelling the request. 422 // history before canceling the request.
375 download_file->CancelDownloadRequest(); 423 download_file->CancelDownloadRequest();
376 return; 424 return;
377 } 425 }
378 426
379 BrowserThread::PostTask( 427 BrowserThread::PostTask(
380 BrowserThread::UI, FROM_HERE, 428 BrowserThread::UI, FROM_HERE,
381 NewRunnableMethod(download_manager, 429 NewRunnableMethod(download_manager,
382 &DownloadManager::DownloadCancelled, id)); 430 &DownloadManager::OnDownloadError,
431 id,
432 download_file->bytes_so_far(),
433 rename_error));
383 } 434 }
384 435
385 void DownloadFileManager::EraseDownload(int id) { 436 void DownloadFileManager::EraseDownload(int id) {
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 437 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
387 438
388 if (!ContainsKey(downloads_, id)) 439 if (!ContainsKey(downloads_, id))
389 return; 440 return;
390 441
391 DownloadFile* download_file = downloads_[id]; 442 DownloadFile* download_file = downloads_[id];
392 443
393 VLOG(20) << " " << __FUNCTION__ << "()" 444 VLOG(20) << " " << __FUNCTION__ << "()"
394 << " id = " << id 445 << " id = " << id
395 << " download_file = " << download_file->DebugString(); 446 << " download_file = " << download_file->DebugString();
396 447
397 downloads_.erase(id); 448 downloads_.erase(id);
398 449
399 delete download_file; 450 delete download_file;
400 451
401 if (downloads_.empty()) 452 if (downloads_.empty())
402 StopUpdateTimer(); 453 StopUpdateTimer();
403 } 454 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698