| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |