Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/download/download_file_manager.h" | 5 #include "chrome/browser/download/download_file_manager.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/stl_util-inl.h" | 8 #include "base/stl_util-inl.h" |
| 9 #include "base/task.h" | 9 #include "base/task.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 void DownloadFileManager::OnShutdown() { | 71 void DownloadFileManager::OnShutdown() { |
| 72 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 72 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 73 StopUpdateTimer(); | 73 StopUpdateTimer(); |
| 74 STLDeleteValues(&downloads_); | 74 STLDeleteValues(&downloads_); |
| 75 } | 75 } |
| 76 | 76 |
| 77 void DownloadFileManager::CreateDownloadFile( | 77 void DownloadFileManager::CreateDownloadFile( |
| 78 DownloadCreateInfo* info, DownloadManager* download_manager) { | 78 DownloadCreateInfo* info, DownloadManager* download_manager) { |
| 79 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 79 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 80 | 80 |
| 81 scoped_ptr<DownloadFile> download_file( | 81 // See if we are reusing a download ID. |
| 82 new DownloadFile(info, download_manager)); | 82 DownloadFile* download_file = NULL; |
| 83 if (!download_file->Initialize()) { | 83 if (info->download_id != -1) { |
| 84 ChromeThread::PostTask( | 84 DownloadFileMap::iterator item = downloads_.find(info->download_id); |
|
Paweł Hajdan Jr.
2010/10/01 09:03:55
This is wrong, as said (and I think fixed) in http
| |
| 85 ChromeThread::IO, FROM_HERE, | 85 if (item != downloads_.end()) { |
| 86 NewRunnableFunction(&download_util::CancelDownloadRequest, | 86 download_file = item->second; |
| 87 resource_dispatcher_host_, | 87 download_file->ReOpen(); |
| 88 info->child_id, | 88 } |
| 89 info->request_id)); | 89 } |
| 90 delete info; | 90 if (!download_file) { |
| 91 return; | 91 download_file = new DownloadFile(info, download_manager); |
| 92 if (!download_file->Initialize()) { | |
| 93 ChromeThread::PostTask( | |
| 94 ChromeThread::IO, | |
| 95 FROM_HERE, | |
| 96 NewRunnableFunction(&download_util::CancelDownloadRequest, | |
| 97 resource_dispatcher_host_, | |
| 98 info->child_id, | |
| 99 info->request_id)); | |
| 100 delete info; | |
| 101 return; | |
| 102 } | |
| 103 | |
| 104 DCHECK(GetDownloadFile(info->download_id) == NULL); | |
| 105 downloads_[info->download_id] = download_file; | |
| 92 } | 106 } |
| 93 | 107 |
| 94 DCHECK(GetDownloadFile(info->download_id) == NULL); | |
| 95 downloads_[info->download_id] = download_file.release(); | |
| 96 // TODO(phajdan.jr): fix the duplication of path info below. | 108 // TODO(phajdan.jr): fix the duplication of path info below. |
| 97 info->path = info->save_info.file_path; | 109 info->path = info->save_info.file_path; |
| 98 | 110 |
| 99 // The file is now ready, we can un-pause the request and start saving data. | 111 // The file is now ready, we can un-pause the request and start saving data. |
| 100 ChromeThread::PostTask( | 112 ChromeThread::PostTask( |
| 101 ChromeThread::IO, FROM_HERE, | 113 ChromeThread::IO, |
| 102 NewRunnableMethod(this, &DownloadFileManager::ResumeDownloadRequest, | 114 FROM_HERE, |
| 103 info->child_id, info->request_id)); | 115 NewRunnableMethod(this, |
| 116 &DownloadFileManager::ResumeDownloadRequest, | |
| 117 info->child_id, | |
| 118 info->request_id)); | |
| 104 | 119 |
| 105 StartUpdateTimer(); | 120 StartUpdateTimer(); |
| 106 | 121 |
| 107 ChromeThread::PostTask( | 122 ChromeThread::PostTask( |
| 108 ChromeThread::UI, FROM_HERE, | 123 ChromeThread::UI, |
| 124 FROM_HERE, | |
| 109 NewRunnableMethod(download_manager, | 125 NewRunnableMethod(download_manager, |
| 110 &DownloadManager::StartDownload, info)); | 126 &DownloadManager::StartDownload, |
| 127 info)); | |
| 111 } | 128 } |
| 112 | 129 |
| 113 void DownloadFileManager::ResumeDownloadRequest(int child_id, int request_id) { | 130 void DownloadFileManager::ResumeDownloadRequest(int child_id, int request_id) { |
| 114 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | 131 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 115 | 132 |
| 116 // This balances the pause in DownloadResourceHandler::OnResponseStarted. | 133 // This balances the pause in DownloadResourceHandler::OnResponseStarted. |
| 117 resource_dispatcher_host_->PauseRequest(child_id, request_id, false); | 134 resource_dispatcher_host_->PauseRequest(child_id, request_id, false); |
| 118 } | 135 } |
| 119 | 136 |
| 120 DownloadFile* DownloadFileManager::GetDownloadFile(int id) { | 137 DownloadFile* DownloadFileManager::GetDownloadFile(int id) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 info->request_id)); | 189 info->request_id)); |
| 173 delete info; | 190 delete info; |
| 174 return; | 191 return; |
| 175 } | 192 } |
| 176 | 193 |
| 177 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 194 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 178 NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile, | 195 NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile, |
| 179 info, manager)); | 196 info, manager)); |
| 180 } | 197 } |
| 181 | 198 |
| 199 int DownloadFileManager::GetDownloadId(const GURL& url, | |
| 200 const FilePath& path) const { | |
| 201 FilePath crpath = download_util::GetCrDownloadPath(path); | |
| 202 DownloadFileMap::const_iterator it = downloads_.begin(); | |
| 203 DownloadFileMap::const_iterator last = downloads_.end(); | |
| 204 for (; it != last; ++it) { | |
| 205 const DownloadFile* download = it->second; | |
| 206 if (download && (download->MatchesUrlAndPath(url, crpath))) | |
| 207 return download->id(); | |
| 208 } | |
| 209 return -1; | |
| 210 } | |
| 211 | |
| 182 // We don't forward an update to the UI thread here, since we want to throttle | 212 // We don't forward an update to the UI thread here, since we want to throttle |
| 183 // the UI update rate via a periodic timer. If the user has cancelled the | 213 // the UI update rate via a periodic timer. If the user has cancelled the |
| 184 // download (in the UI thread), we may receive a few more updates before the IO | 214 // download (in the UI thread), we may receive a few more updates before the IO |
| 185 // thread gets the cancel message: we just delete the data since the | 215 // thread gets the cancel message: we just delete the data since the |
| 186 // DownloadFile has been deleted. | 216 // DownloadFile has been deleted. |
| 187 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { | 217 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { |
| 188 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 218 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 189 std::vector<DownloadBuffer::Contents> contents; | 219 std::vector<DownloadBuffer::Contents> contents; |
| 190 { | 220 { |
| 191 AutoLock auto_lock(buffer->lock); | 221 AutoLock auto_lock(buffer->lock); |
| 192 contents.swap(buffer->contents); | 222 contents.swap(buffer->contents); |
| 193 } | 223 } |
| 194 | 224 |
| 195 DownloadFile* download = GetDownloadFile(id); | 225 DownloadFile* download = GetDownloadFile(id); |
| 196 for (size_t i = 0; i < contents.size(); ++i) { | 226 for (size_t i = 0; i < contents.size(); ++i) { |
| 197 net::IOBuffer* data = contents[i].first; | 227 net::IOBuffer* data = contents[i].first; |
| 198 const int data_len = contents[i].second; | 228 const int data_len = contents[i].second; |
| 199 if (download) | 229 if (download) |
| 200 download->AppendDataToFile(data->data(), data_len); | 230 download->AppendDataToFile(data->data(), data_len); |
| 201 data->Release(); | 231 data->Release(); |
| 202 } | 232 } |
| 203 } | 233 } |
| 204 | 234 |
| 205 void DownloadFileManager::OnResponseCompleted(int id, DownloadBuffer* buffer) { | 235 void DownloadFileManager::OnResponseCompleted( |
| 236 int id, | |
| 237 DownloadBuffer* buffer, | |
| 238 int os_error, | |
| 239 const std::string& security_info) { | |
| 206 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 240 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 207 delete buffer; | 241 delete buffer; |
| 208 DownloadFileMap::iterator it = downloads_.find(id); | 242 DownloadFile* download = GetDownloadFile(id); |
| 209 if (it != downloads_.end()) { | 243 if (download) { |
| 210 DownloadFile* download = it->second; | 244 // Closes the file. In the case of an error, it closes the temporary |
| 245 // (.crdownload) one; otherwise it closes the original download file name. | |
| 246 DCHECK(!os_error == | |
| 247 !download_util::IsCrDownloadPath(download->full_path())); | |
| 211 download->Finish(); | 248 download->Finish(); |
| 212 | 249 |
| 213 DownloadManager* download_manager = download->GetDownloadManager(); | 250 DownloadManager* download_manager = download->GetDownloadManager(); |
| 214 if (download_manager) { | 251 if (download_manager) { |
| 215 ChromeThread::PostTask( | 252 ChromeThread::PostTask( |
| 216 ChromeThread::UI, FROM_HERE, | 253 ChromeThread::UI, |
| 254 FROM_HERE, | |
| 217 NewRunnableMethod( | 255 NewRunnableMethod( |
| 218 download_manager, &DownloadManager::OnAllDataSaved, | 256 download_manager, |
| 219 id, download->bytes_so_far())); | 257 &DownloadManager::OnResponseCompleted, |
| 258 id, | |
| 259 download->bytes_so_far(), | |
| 260 os_error)); | |
| 220 } | 261 } |
| 221 | 262 |
| 222 // We need to keep the download around until the UI thread has finalized | 263 // We need to keep the download around until the UI thread has finalized |
| 223 // the name. | 264 // the name. |
| 224 if (download->path_renamed()) { | 265 if (download->path_renamed()) { |
| 225 downloads_.erase(it); | 266 downloads_.erase(downloads_.find(id)); |
| 226 delete download; | 267 delete download; |
| 227 } | 268 } |
| 228 } | 269 } |
| 229 | 270 |
| 230 if (downloads_.empty()) | 271 if (downloads_.empty()) |
| 231 StopUpdateTimer(); | 272 StopUpdateTimer(); |
| 232 } | 273 } |
| 233 | 274 |
| 234 // This method will be sent via a user action, or shutdown on the UI thread, and | 275 // This method will be sent via a user action, or shutdown on the UI thread, and |
| 235 // run on the download thread. Since this message has been sent from the UI | 276 // run on the download thread. Since this message has been sent from the UI |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 downloads_.erase((*i)->id()); | 312 downloads_.erase((*i)->id()); |
| 272 delete *i; | 313 delete *i; |
| 273 } | 314 } |
| 274 } | 315 } |
| 275 | 316 |
| 276 // Actions from the UI thread and run on the download thread | 317 // Actions from the UI thread and run on the download thread |
| 277 | 318 |
| 278 // The DownloadManager in the UI thread has provided an intermediate .crdownload | 319 // The DownloadManager in the UI thread has provided an intermediate .crdownload |
| 279 // name for the download specified by 'id'. Rename the in progress download. | 320 // name for the download specified by 'id'. Rename the in progress download. |
| 280 void DownloadFileManager::OnIntermediateDownloadName( | 321 void DownloadFileManager::OnIntermediateDownloadName( |
| 281 int id, const FilePath& full_path, DownloadManager* download_manager) | 322 int id, const FilePath& full_path, DownloadManager* download_manager) { |
| 282 { | |
| 283 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 323 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 284 DownloadFileMap::iterator it = downloads_.find(id); | 324 DownloadFileMap::iterator it = downloads_.find(id); |
| 285 if (it == downloads_.end()) | 325 if (it == downloads_.end()) |
| 286 return; | 326 return; |
| 287 | 327 |
| 288 DownloadFile* download = it->second; | 328 DownloadFile* download = it->second; |
| 289 if (!download->Rename(full_path, false)) { | 329 if (!download->Rename(full_path, false)) { |
| 290 // Error. Between the time the UI thread generated 'full_path' to the time | 330 // Error. Between the time the UI thread generated 'full_path' to the time |
| 291 // this code runs, something happened that prevents us from renaming. | 331 // this code runs, something happened that prevents us from renaming. |
| 292 CancelDownloadOnRename(id); | 332 CancelDownloadOnRename(id); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 357 if (!download_manager) { | 397 if (!download_manager) { |
| 358 download->CancelDownloadRequest(resource_dispatcher_host_); | 398 download->CancelDownloadRequest(resource_dispatcher_host_); |
| 359 return; | 399 return; |
| 360 } | 400 } |
| 361 | 401 |
| 362 ChromeThread::PostTask( | 402 ChromeThread::PostTask( |
| 363 ChromeThread::UI, FROM_HERE, | 403 ChromeThread::UI, FROM_HERE, |
| 364 NewRunnableMethod(download_manager, | 404 NewRunnableMethod(download_manager, |
| 365 &DownloadManager::DownloadCancelled, id)); | 405 &DownloadManager::DownloadCancelled, id)); |
| 366 } | 406 } |
| OLD | NEW |