| 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 <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 15 #include "content/browser/download/base_file.h" | 15 #include "content/browser/download/base_file.h" |
| 16 #include "content/browser/download/download_buffer.h" | 16 #include "content/browser/download/download_buffer.h" |
| 17 #include "content/browser/download/download_create_info.h" | 17 #include "content/browser/download/download_create_info.h" |
| 18 #include "content/browser/download/download_file.h" | 18 #include "content/browser/download/download_file_impl.h" |
| 19 #include "content/browser/download/download_manager.h" | 19 #include "content/browser/download/download_manager.h" |
| 20 #include "content/browser/download/download_request_handle.h" | 20 #include "content/browser/download/download_request_handle.h" |
| 21 #include "content/browser/download/download_stats.h" | 21 #include "content/browser/download/download_stats.h" |
| 22 #include "content/browser/renderer_host/resource_dispatcher_host.h" | 22 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
| 23 #include "content/browser/tab_contents/tab_contents.h" | 23 #include "content/browser/tab_contents/tab_contents.h" |
| 24 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
| 25 #include "content/public/browser/download_manager_delegate.h" | 25 #include "content/public/browser/download_manager_delegate.h" |
| 26 #include "googleurl/src/gurl.h" | 26 #include "googleurl/src/gurl.h" |
| 27 #include "net/base/io_buffer.h" | 27 #include "net/base/io_buffer.h" |
| 28 | 28 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 void DownloadFileManager::CreateDownloadFile( | 60 void DownloadFileManager::CreateDownloadFile( |
| 61 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle, | 61 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle, |
| 62 DownloadManager* download_manager, bool get_hash) { | 62 DownloadManager* download_manager, bool get_hash) { |
| 63 DCHECK(info); | 63 DCHECK(info); |
| 64 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); | 64 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); |
| 65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 66 | 66 |
| 67 // Life of |info| ends here. No more references to it after this method. | 67 // Life of |info| ends here. No more references to it after this method. |
| 68 scoped_ptr<DownloadCreateInfo> infop(info); | 68 scoped_ptr<DownloadCreateInfo> infop(info); |
| 69 | 69 |
| 70 scoped_ptr<DownloadFile> | 70 scoped_ptr<DownloadFile> download_file( |
| 71 download_file(new DownloadFile(info, | 71 new DownloadFileImpl(info, |
| 72 new DownloadRequestHandle(request_handle), | 72 new DownloadRequestHandle(request_handle), |
| 73 download_manager)); | 73 download_manager)); |
| 74 if (net::OK != download_file->Initialize(get_hash)) { | 74 if (net::OK != download_file->Initialize(get_hash)) { |
| 75 request_handle.CancelRequest(); | 75 request_handle.CancelRequest(); |
| 76 return; | 76 return; |
| 77 } | 77 } |
| 78 | 78 |
| 79 DCHECK(GetDownloadFile(info->download_id) == NULL); | 79 DCHECK(GetDownloadFile(info->download_id) == NULL); |
| 80 downloads_[info->download_id] = download_file.release(); | 80 downloads_[info->download_id] = download_file.release(); |
| 81 | 81 |
| 82 // The file is now ready, we can un-pause the request and start saving data. | 82 // The file is now ready, we can un-pause the request and start saving data. |
| 83 request_handle.ResumeRequest(); | 83 request_handle.ResumeRequest(); |
| 84 | 84 |
| 85 StartUpdateTimer(); | 85 StartUpdateTimer(); |
| 86 | 86 |
| 87 BrowserThread::PostTask( | 87 BrowserThread::PostTask( |
| 88 BrowserThread::UI, FROM_HERE, | 88 BrowserThread::UI, FROM_HERE, |
| 89 base::Bind(&DownloadManager::StartDownload, download_manager, | 89 base::Bind(&DownloadManager::StartDownload, download_manager, |
| 90 info->download_id.local())); | 90 info->download_id.local())); |
| 91 } | 91 } |
| 92 | 92 |
| 93 DownloadFile* DownloadFileManager::GetDownloadFile(DownloadId global_id) { | 93 DownloadFile* DownloadFileManager::GetDownloadFile( |
| 94 DownloadId global_id) { |
| 94 DownloadFileMap::iterator it = downloads_.find(global_id); | 95 DownloadFileMap::iterator it = downloads_.find(global_id); |
| 95 return it == downloads_.end() ? NULL : it->second; | 96 return it == downloads_.end() ? NULL : it->second; |
| 96 } | 97 } |
| 97 | 98 |
| 98 void DownloadFileManager::StartUpdateTimer() { | 99 void DownloadFileManager::StartUpdateTimer() { |
| 99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 100 if (!update_timer_.IsRunning()) { | 101 if (!update_timer_.IsRunning()) { |
| 101 update_timer_.Start(FROM_HERE, | 102 update_timer_.Start(FROM_HERE, |
| 102 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), | 103 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), |
| 103 this, &DownloadFileManager::UpdateInProgressDownloads); | 104 this, &DownloadFileManager::UpdateInProgressDownloads); |
| 104 } | 105 } |
| 105 } | 106 } |
| 106 | 107 |
| 107 void DownloadFileManager::StopUpdateTimer() { | 108 void DownloadFileManager::StopUpdateTimer() { |
| 108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 109 update_timer_.Stop(); | 110 update_timer_.Stop(); |
| 110 } | 111 } |
| 111 | 112 |
| 112 void DownloadFileManager::UpdateInProgressDownloads() { | 113 void DownloadFileManager::UpdateInProgressDownloads() { |
| 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 114 for (DownloadFileMap::iterator i = downloads_.begin(); | 115 for (DownloadFileMap::iterator i = downloads_.begin(); |
| 115 i != downloads_.end(); ++i) { | 116 i != downloads_.end(); ++i) { |
| 116 DownloadId global_id = i->first; | 117 DownloadId global_id = i->first; |
| 117 DownloadFile* download_file = i->second; | 118 DownloadFile* download_file = i->second; |
| 118 DownloadManager* manager = download_file->GetDownloadManager(); | 119 DownloadManager* manager = download_file->GetDownloadManager(); |
| 119 if (manager) { | 120 if (manager) { |
| 120 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 121 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 121 base::Bind(&DownloadManager::UpdateDownload, manager, | 122 base::Bind(&DownloadManager::UpdateDownload, manager, |
| 122 global_id.local(), download_file->bytes_so_far())); | 123 global_id.local(), download_file->BytesSoFar())); |
| 123 } | 124 } |
| 124 } | 125 } |
| 125 } | 126 } |
| 126 | 127 |
| 127 void DownloadFileManager::StartDownload( | 128 void DownloadFileManager::StartDownload( |
| 128 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) { | 129 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) { |
| 129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 130 DCHECK(info); | 131 DCHECK(info); |
| 131 | 132 |
| 132 DownloadManager* manager = request_handle.GetDownloadManager(); | 133 DownloadManager* manager = request_handle.GetDownloadManager(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 net::IOBuffer* data = (*contents)[i].first; | 167 net::IOBuffer* data = (*contents)[i].first; |
| 167 const int data_len = (*contents)[i].second; | 168 const int data_len = (*contents)[i].second; |
| 168 if (!had_error && download_file) { | 169 if (!had_error && download_file) { |
| 169 net::Error write_result = | 170 net::Error write_result = |
| 170 download_file->AppendDataToFile(data->data(), data_len); | 171 download_file->AppendDataToFile(data->data(), data_len); |
| 171 if (write_result != net::OK) { | 172 if (write_result != net::OK) { |
| 172 // Write failed: interrupt the download. | 173 // Write failed: interrupt the download. |
| 173 DownloadManager* download_manager = download_file->GetDownloadManager(); | 174 DownloadManager* download_manager = download_file->GetDownloadManager(); |
| 174 had_error = true; | 175 had_error = true; |
| 175 | 176 |
| 176 int64 bytes_downloaded = download_file->bytes_so_far(); | 177 int64 bytes_downloaded = download_file->BytesSoFar(); |
| 177 // Calling this here in case we get more data, to avoid | 178 // Calling this here in case we get more data, to avoid |
| 178 // processing data after an error. That could lead to | 179 // processing data after an error. That could lead to |
| 179 // files that are corrupted if the later processing succeeded. | 180 // files that are corrupted if the later processing succeeded. |
| 180 CancelDownload(global_id); | 181 CancelDownload(global_id); |
| 181 download_file = NULL; // Was deleted in |CancelDownload|. | 182 download_file = NULL; // Was deleted in |CancelDownload|. |
| 182 | 183 |
| 183 if (download_manager) { | 184 if (download_manager) { |
| 184 BrowserThread::PostTask( | 185 BrowserThread::PostTask( |
| 185 BrowserThread::UI, FROM_HERE, | 186 BrowserThread::UI, FROM_HERE, |
| 186 base::Bind(&DownloadManager::OnDownloadInterrupted, | 187 base::Bind(&DownloadManager::OnDownloadInterrupted, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 216 | 217 |
| 217 std::string hash; | 218 std::string hash; |
| 218 if (!download_file->GetSha256Hash(&hash) || BaseFile::IsEmptySha256Hash(hash)) | 219 if (!download_file->GetSha256Hash(&hash) || BaseFile::IsEmptySha256Hash(hash)) |
| 219 hash.clear(); | 220 hash.clear(); |
| 220 | 221 |
| 221 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) { | 222 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 222 BrowserThread::PostTask( | 223 BrowserThread::PostTask( |
| 223 BrowserThread::UI, FROM_HERE, | 224 BrowserThread::UI, FROM_HERE, |
| 224 base::Bind(&DownloadManager::OnResponseCompleted, | 225 base::Bind(&DownloadManager::OnResponseCompleted, |
| 225 download_manager, global_id.local(), | 226 download_manager, global_id.local(), |
| 226 download_file->bytes_so_far(), hash)); | 227 download_file->BytesSoFar(), hash)); |
| 227 } else { | 228 } else { |
| 228 BrowserThread::PostTask( | 229 BrowserThread::PostTask( |
| 229 BrowserThread::UI, FROM_HERE, | 230 BrowserThread::UI, FROM_HERE, |
| 230 base::Bind(&DownloadManager::OnDownloadInterrupted, | 231 base::Bind(&DownloadManager::OnDownloadInterrupted, |
| 231 download_manager, global_id.local(), | 232 download_manager, global_id.local(), |
| 232 download_file->bytes_so_far(), reason)); | 233 download_file->BytesSoFar(), reason)); |
| 233 } | 234 } |
| 234 // We need to keep the download around until the UI thread has finalized | 235 // We need to keep the download around until the UI thread has finalized |
| 235 // the name. | 236 // the name. |
| 236 } | 237 } |
| 237 | 238 |
| 238 // This method will be sent via a user action, or shutdown on the UI thread, and | 239 // This method will be sent via a user action, or shutdown on the UI thread, and |
| 239 // run on the download thread. Since this message has been sent from the UI | 240 // run on the download thread. Since this message has been sent from the UI |
| 240 // thread, the download may have already completed and won't exist in our map. | 241 // thread, the download may have already completed and won't exist in our map. |
| 241 void DownloadFileManager::CancelDownload(DownloadId global_id) { | 242 void DownloadFileManager::CancelDownload(DownloadId global_id) { |
| 242 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id; | 243 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 i != downloads_.end(); ++i) { | 281 i != downloads_.end(); ++i) { |
| 281 DownloadFile* download_file = i->second; | 282 DownloadFile* download_file = i->second; |
| 282 if (download_file->GetDownloadManager() == manager) { | 283 if (download_file->GetDownloadManager() == manager) { |
| 283 download_file->CancelDownloadRequest(); | 284 download_file->CancelDownloadRequest(); |
| 284 to_remove.insert(download_file); | 285 to_remove.insert(download_file); |
| 285 } | 286 } |
| 286 } | 287 } |
| 287 | 288 |
| 288 for (std::set<DownloadFile*>::iterator i = to_remove.begin(); | 289 for (std::set<DownloadFile*>::iterator i = to_remove.begin(); |
| 289 i != to_remove.end(); ++i) { | 290 i != to_remove.end(); ++i) { |
| 290 downloads_.erase((*i)->global_id()); | 291 downloads_.erase((*i)->GlobalId()); |
| 291 delete *i; | 292 delete *i; |
| 292 } | 293 } |
| 293 } | 294 } |
| 294 | 295 |
| 295 // Actions from the UI thread and run on the download thread | 296 // Actions from the UI thread and run on the download thread |
| 296 | 297 |
| 297 // The DownloadManager in the UI thread has provided an intermediate .crdownload | 298 // The DownloadManager in the UI thread has provided an intermediate .crdownload |
| 298 // name for the download specified by 'id'. Rename the in progress download. | 299 // name for the download specified by 'id'. Rename the in progress download. |
| 299 // | 300 // |
| 300 // There are 2 possible rename cases where this method can be called: | 301 // There are 2 possible rename cases where this method can be called: |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 // need to do it here. The normal path will also update the download | 401 // need to do it here. The normal path will also update the download |
| 401 // history before canceling the request. | 402 // history before canceling the request. |
| 402 download_file->CancelDownloadRequest(); | 403 download_file->CancelDownloadRequest(); |
| 403 return; | 404 return; |
| 404 } | 405 } |
| 405 | 406 |
| 406 BrowserThread::PostTask( | 407 BrowserThread::PostTask( |
| 407 BrowserThread::UI, FROM_HERE, | 408 BrowserThread::UI, FROM_HERE, |
| 408 base::Bind(&DownloadManager::OnDownloadInterrupted, | 409 base::Bind(&DownloadManager::OnDownloadInterrupted, |
| 409 download_manager, global_id.local(), | 410 download_manager, global_id.local(), |
| 410 download_file->bytes_so_far(), | 411 download_file->BytesSoFar(), |
| 411 ConvertNetErrorToInterruptReason( | 412 ConvertNetErrorToInterruptReason( |
| 412 rename_error, DOWNLOAD_INTERRUPT_FROM_DISK))); | 413 rename_error, DOWNLOAD_INTERRUPT_FROM_DISK))); |
| 413 } | 414 } |
| 414 | 415 |
| 415 void DownloadFileManager::EraseDownload(DownloadId global_id) { | 416 void DownloadFileManager::EraseDownload(DownloadId global_id) { |
| 416 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 417 | 418 |
| 418 if (!ContainsKey(downloads_, global_id)) | 419 if (!ContainsKey(downloads_, global_id)) |
| 419 return; | 420 return; |
| 420 | 421 |
| 421 DownloadFile* download_file = downloads_[global_id]; | 422 DownloadFile* download_file = downloads_[global_id]; |
| 422 | 423 |
| 423 VLOG(20) << " " << __FUNCTION__ << "()" | 424 VLOG(20) << " " << __FUNCTION__ << "()" |
| 424 << " id = " << global_id | 425 << " id = " << global_id |
| 425 << " download_file = " << download_file->DebugString(); | 426 << " download_file = " << download_file->DebugString(); |
| 426 | 427 |
| 427 downloads_.erase(global_id); | 428 downloads_.erase(global_id); |
| 428 | 429 |
| 429 delete download_file; | 430 delete download_file; |
| 430 | 431 |
| 431 if (downloads_.empty()) | 432 if (downloads_.empty()) |
| 432 StopUpdateTimer(); | 433 StopUpdateTimer(); |
| 433 } | 434 } |
| OLD | NEW |