| 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" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 } | 48 } |
| 49 | 49 |
| 50 void DownloadFileManager::OnShutdown() { | 50 void DownloadFileManager::OnShutdown() { |
| 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 52 StopUpdateTimer(); | 52 StopUpdateTimer(); |
| 53 STLDeleteValues(&downloads_); | 53 STLDeleteValues(&downloads_); |
| 54 } | 54 } |
| 55 | 55 |
| 56 void DownloadFileManager::CreateDownloadFile( | 56 void DownloadFileManager::CreateDownloadFile( |
| 57 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle, | 57 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle, |
| 58 DownloadManager* download_manager, bool get_hash) { | 58 DownloadManagerInterface* download_manager, bool get_hash) { |
| 59 DCHECK(info); | 59 DCHECK(info); |
| 60 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); | 60 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); |
| 61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 62 | 62 |
| 63 // Life of |info| ends here. No more references to it after this method. | 63 // Life of |info| ends here. No more references to it after this method. |
| 64 scoped_ptr<DownloadCreateInfo> infop(info); | 64 scoped_ptr<DownloadCreateInfo> infop(info); |
| 65 | 65 |
| 66 scoped_ptr<DownloadFile> | 66 scoped_ptr<DownloadFile> |
| 67 download_file(new DownloadFile(info, request_handle, download_manager)); | 67 download_file(new DownloadFile(info, request_handle, download_manager)); |
| 68 if (net::OK != download_file->Initialize(get_hash)) { | 68 if (net::OK != download_file->Initialize(get_hash)) { |
| 69 request_handle.CancelRequest(); | 69 request_handle.CancelRequest(); |
| 70 return; | 70 return; |
| 71 } | 71 } |
| 72 | 72 |
| 73 DCHECK(GetDownloadFile(info->download_id) == NULL); | 73 DCHECK(GetDownloadFile(info->download_id) == NULL); |
| 74 downloads_[info->download_id] = download_file.release(); | 74 downloads_[info->download_id] = download_file.release(); |
| 75 | 75 |
| 76 // The file is now ready, we can un-pause the request and start saving data. | 76 // The file is now ready, we can un-pause the request and start saving data. |
| 77 request_handle.ResumeRequest(); | 77 request_handle.ResumeRequest(); |
| 78 | 78 |
| 79 StartUpdateTimer(); | 79 StartUpdateTimer(); |
| 80 | 80 |
| 81 BrowserThread::PostTask( | 81 BrowserThread::PostTask( |
| 82 BrowserThread::UI, FROM_HERE, | 82 BrowserThread::UI, FROM_HERE, |
| 83 base::Bind(&DownloadManager::StartDownload, download_manager, | 83 base::Bind(&DownloadManagerInterface::StartDownload, download_manager, |
| 84 info->download_id.local())); | 84 info->download_id.local())); |
| 85 } | 85 } |
| 86 | 86 |
| 87 DownloadFile* DownloadFileManager::GetDownloadFile(DownloadId global_id) { | 87 DownloadFile* DownloadFileManager::GetDownloadFile(DownloadId global_id) { |
| 88 DownloadFileMap::iterator it = downloads_.find(global_id); | 88 DownloadFileMap::iterator it = downloads_.find(global_id); |
| 89 return it == downloads_.end() ? NULL : it->second; | 89 return it == downloads_.end() ? NULL : it->second; |
| 90 } | 90 } |
| 91 | 91 |
| 92 void DownloadFileManager::StartUpdateTimer() { | 92 void DownloadFileManager::StartUpdateTimer() { |
| 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 94 if (!update_timer_.IsRunning()) { | 94 if (!update_timer_.IsRunning()) { |
| 95 update_timer_.Start(FROM_HERE, | 95 update_timer_.Start(FROM_HERE, |
| 96 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), | 96 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), |
| 97 this, &DownloadFileManager::UpdateInProgressDownloads); | 97 this, &DownloadFileManager::UpdateInProgressDownloads); |
| 98 } | 98 } |
| 99 } | 99 } |
| 100 | 100 |
| 101 void DownloadFileManager::StopUpdateTimer() { | 101 void DownloadFileManager::StopUpdateTimer() { |
| 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 103 update_timer_.Stop(); | 103 update_timer_.Stop(); |
| 104 } | 104 } |
| 105 | 105 |
| 106 void DownloadFileManager::UpdateInProgressDownloads() { | 106 void DownloadFileManager::UpdateInProgressDownloads() { |
| 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 108 for (DownloadFileMap::iterator i = downloads_.begin(); | 108 for (DownloadFileMap::iterator i = downloads_.begin(); |
| 109 i != downloads_.end(); ++i) { | 109 i != downloads_.end(); ++i) { |
| 110 DownloadId global_id = i->first; | 110 DownloadId global_id = i->first; |
| 111 DownloadFile* download_file = i->second; | 111 DownloadFile* download_file = i->second; |
| 112 DownloadManager* manager = download_file->GetDownloadManager(); | 112 DownloadManagerInterface* manager = download_file->GetDownloadManager(); |
| 113 if (manager) { | 113 if (manager) { |
| 114 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 114 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 115 base::Bind(&DownloadManager::UpdateDownload, manager, | 115 base::Bind(&DownloadManagerInterface::UpdateDownload, manager, |
| 116 global_id.local(), download_file->bytes_so_far())); | 116 global_id.local(), download_file->bytes_so_far())); |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 } | 119 } |
| 120 | 120 |
| 121 void DownloadFileManager::StartDownload( | 121 void DownloadFileManager::StartDownload( |
| 122 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) { | 122 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) { |
| 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 124 DCHECK(info); | 124 DCHECK(info); |
| 125 | 125 |
| 126 DownloadManager* manager = request_handle.GetDownloadManager(); | 126 DownloadManagerInterface* manager = request_handle.GetDownloadManager(); |
| 127 if (!manager) { | 127 if (!manager) { |
| 128 request_handle.CancelRequest(); | 128 request_handle.CancelRequest(); |
| 129 delete info; | 129 delete info; |
| 130 return; | 130 return; |
| 131 } | 131 } |
| 132 | 132 |
| 133 // TODO(phajdan.jr): fix the duplication of path info below. | 133 // TODO(phajdan.jr): fix the duplication of path info below. |
| 134 info->path = info->save_info.file_path; | 134 info->path = info->save_info.file_path; |
| 135 | 135 |
| 136 manager->CreateDownloadItem(info, request_handle); | 136 manager->CreateDownloadItem(info, request_handle); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 155 DownloadFile* download_file = GetDownloadFile(global_id); | 155 DownloadFile* download_file = GetDownloadFile(global_id); |
| 156 bool had_error = false; | 156 bool had_error = false; |
| 157 for (size_t i = 0; i < contents->size(); ++i) { | 157 for (size_t i = 0; i < contents->size(); ++i) { |
| 158 net::IOBuffer* data = (*contents)[i].first; | 158 net::IOBuffer* data = (*contents)[i].first; |
| 159 const int data_len = (*contents)[i].second; | 159 const int data_len = (*contents)[i].second; |
| 160 if (!had_error && download_file) { | 160 if (!had_error && download_file) { |
| 161 net::Error write_result = | 161 net::Error write_result = |
| 162 download_file->AppendDataToFile(data->data(), data_len); | 162 download_file->AppendDataToFile(data->data(), data_len); |
| 163 if (write_result != net::OK) { | 163 if (write_result != net::OK) { |
| 164 // Write failed: interrupt the download. | 164 // Write failed: interrupt the download. |
| 165 DownloadManager* download_manager = download_file->GetDownloadManager(); | 165 DownloadManagerInterface* download_manager = |
| 166 download_file->GetDownloadManager(); |
| 166 had_error = true; | 167 had_error = true; |
| 167 | 168 |
| 168 int64 bytes_downloaded = download_file->bytes_so_far(); | 169 int64 bytes_downloaded = download_file->bytes_so_far(); |
| 169 // Calling this here in case we get more data, to avoid | 170 // Calling this here in case we get more data, to avoid |
| 170 // processing data after an error. That could lead to | 171 // processing data after an error. That could lead to |
| 171 // files that are corrupted if the later processing succeeded. | 172 // files that are corrupted if the later processing succeeded. |
| 172 CancelDownload(global_id); | 173 CancelDownload(global_id); |
| 173 download_file = NULL; // Was deleted in |CancelDownload|. | 174 download_file = NULL; // Was deleted in |CancelDownload|. |
| 174 | 175 |
| 175 if (download_manager) { | 176 if (download_manager) { |
| 176 BrowserThread::PostTask( | 177 BrowserThread::PostTask( |
| 177 BrowserThread::UI, FROM_HERE, | 178 BrowserThread::UI, FROM_HERE, |
| 178 base::Bind(&DownloadManager::OnDownloadInterrupted, | 179 base::Bind(&DownloadManagerInterface::OnDownloadInterrupted, |
| 179 download_manager, global_id.local(), bytes_downloaded, | 180 download_manager, global_id.local(), bytes_downloaded, |
| 180 ConvertNetErrorToInterruptReason( | 181 ConvertNetErrorToInterruptReason( |
| 181 write_result, DOWNLOAD_INTERRUPT_FROM_DISK))); | 182 write_result, DOWNLOAD_INTERRUPT_FROM_DISK))); |
| 182 } | 183 } |
| 183 } | 184 } |
| 184 } | 185 } |
| 185 data->Release(); | 186 data->Release(); |
| 186 } | 187 } |
| 187 } | 188 } |
| 188 | 189 |
| 189 void DownloadFileManager::OnResponseCompleted( | 190 void DownloadFileManager::OnResponseCompleted( |
| 190 DownloadId global_id, | 191 DownloadId global_id, |
| 191 InterruptReason reason, | 192 InterruptReason reason, |
| 192 const std::string& security_info) { | 193 const std::string& security_info) { |
| 193 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id | 194 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id |
| 194 << " reason = " << InterruptReasonDebugString(reason) | 195 << " reason = " << InterruptReasonDebugString(reason) |
| 195 << " security_info = \"" << security_info << "\""; | 196 << " security_info = \"" << security_info << "\""; |
| 196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 197 DownloadFile* download_file = GetDownloadFile(global_id); | 198 DownloadFile* download_file = GetDownloadFile(global_id); |
| 198 if (!download_file) | 199 if (!download_file) |
| 199 return; | 200 return; |
| 200 | 201 |
| 201 download_file->Finish(); | 202 download_file->Finish(); |
| 202 | 203 |
| 203 DownloadManager* download_manager = download_file->GetDownloadManager(); | 204 DownloadManagerInterface* download_manager = |
| 205 download_file->GetDownloadManager(); |
| 204 if (!download_manager) { | 206 if (!download_manager) { |
| 205 CancelDownload(global_id); | 207 CancelDownload(global_id); |
| 206 return; | 208 return; |
| 207 } | 209 } |
| 208 | 210 |
| 209 std::string hash; | 211 std::string hash; |
| 210 if (!download_file->GetSha256Hash(&hash)) | 212 if (!download_file->GetSha256Hash(&hash)) |
| 211 hash.clear(); | 213 hash.clear(); |
| 212 | 214 |
| 213 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) { | 215 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 214 BrowserThread::PostTask( | 216 BrowserThread::PostTask( |
| 215 BrowserThread::UI, FROM_HERE, | 217 BrowserThread::UI, FROM_HERE, |
| 216 base::Bind(&DownloadManager::OnResponseCompleted, | 218 base::Bind(&DownloadManagerInterface::OnResponseCompleted, |
| 217 download_manager, global_id.local(), | 219 download_manager, global_id.local(), |
| 218 download_file->bytes_so_far(), hash)); | 220 download_file->bytes_so_far(), hash)); |
| 219 } else { | 221 } else { |
| 220 BrowserThread::PostTask( | 222 BrowserThread::PostTask( |
| 221 BrowserThread::UI, FROM_HERE, | 223 BrowserThread::UI, FROM_HERE, |
| 222 base::Bind(&DownloadManager::OnDownloadInterrupted, | 224 base::Bind(&DownloadManagerInterface::OnDownloadInterrupted, |
| 223 download_manager, global_id.local(), | 225 download_manager, global_id.local(), |
| 224 download_file->bytes_so_far(), reason)); | 226 download_file->bytes_so_far(), reason)); |
| 225 } | 227 } |
| 226 // We need to keep the download around until the UI thread has finalized | 228 // We need to keep the download around until the UI thread has finalized |
| 227 // the name. | 229 // the name. |
| 228 } | 230 } |
| 229 | 231 |
| 230 // This method will be sent via a user action, or shutdown on the UI thread, and | 232 // This method will be sent via a user action, or shutdown on the UI thread, and |
| 231 // run on the download thread. Since this message has been sent from the UI | 233 // run on the download thread. Since this message has been sent from the UI |
| 232 // thread, the download may have already completed and won't exist in our map. | 234 // thread, the download may have already completed and won't exist in our map. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 255 | 257 |
| 256 VLOG(20) << " " << __FUNCTION__ << "()" | 258 VLOG(20) << " " << __FUNCTION__ << "()" |
| 257 << " id = " << global_id | 259 << " id = " << global_id |
| 258 << " download_file = " << download_file->DebugString(); | 260 << " download_file = " << download_file->DebugString(); |
| 259 | 261 |
| 260 download_file->Detach(); | 262 download_file->Detach(); |
| 261 | 263 |
| 262 EraseDownload(global_id); | 264 EraseDownload(global_id); |
| 263 } | 265 } |
| 264 | 266 |
| 265 void DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) { | 267 void DownloadFileManager::OnDownloadManagerShutdown( |
| 268 DownloadManagerInterface* manager) { |
| 266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 267 DCHECK(manager); | 270 DCHECK(manager); |
| 268 | 271 |
| 269 std::set<DownloadFile*> to_remove; | 272 std::set<DownloadFile*> to_remove; |
| 270 | 273 |
| 271 for (DownloadFileMap::iterator i = downloads_.begin(); | 274 for (DownloadFileMap::iterator i = downloads_.begin(); |
| 272 i != downloads_.end(); ++i) { | 275 i != downloads_.end(); ++i) { |
| 273 DownloadFile* download_file = i->second; | 276 DownloadFile* download_file = i->second; |
| 274 if (download_file->GetDownloadManager() == manager) { | 277 if (download_file->GetDownloadManager() == manager) { |
| 275 download_file->CancelDownloadRequest(); | 278 download_file->CancelDownloadRequest(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id | 330 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id |
| 328 << " overwrite_existing_file = " << overwrite_existing_file | 331 << " overwrite_existing_file = " << overwrite_existing_file |
| 329 << " full_path = \"" << full_path.value() << "\""; | 332 << " full_path = \"" << full_path.value() << "\""; |
| 330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 331 | 334 |
| 332 DownloadFile* download_file = GetDownloadFile(global_id); | 335 DownloadFile* download_file = GetDownloadFile(global_id); |
| 333 if (!download_file) | 336 if (!download_file) |
| 334 return; | 337 return; |
| 335 | 338 |
| 336 DCHECK(download_file->GetDownloadManager()); | 339 DCHECK(download_file->GetDownloadManager()); |
| 337 DownloadManager* download_manager = download_file->GetDownloadManager(); | 340 DownloadManagerInterface* download_manager = |
| 341 download_file->GetDownloadManager(); |
| 338 | 342 |
| 339 VLOG(20) << __FUNCTION__ << "()" | 343 VLOG(20) << __FUNCTION__ << "()" |
| 340 << " download_file = " << download_file->DebugString(); | 344 << " download_file = " << download_file->DebugString(); |
| 341 | 345 |
| 342 int uniquifier = 0; | 346 int uniquifier = 0; |
| 343 FilePath new_path = full_path; | 347 FilePath new_path = full_path; |
| 344 if (!overwrite_existing_file) { | 348 if (!overwrite_existing_file) { |
| 345 // Make our name unique at this point, as if a dangerous file is | 349 // Make our name unique at this point, as if a dangerous file is |
| 346 // downloading and a 2nd download is started for a file with the same | 350 // downloading and a 2nd download is started for a file with the same |
| 347 // name, they would have the same path. This is because we uniquify | 351 // name, they would have the same path. This is because we uniquify |
| (...skipping 17 matching lines...) Expand all Loading... |
| 365 } | 369 } |
| 366 | 370 |
| 367 #if defined(OS_MACOSX) | 371 #if defined(OS_MACOSX) |
| 368 // Done here because we only want to do this once; see | 372 // Done here because we only want to do this once; see |
| 369 // http://crbug.com/13120 for details. | 373 // http://crbug.com/13120 for details. |
| 370 download_file->AnnotateWithSourceInformation(); | 374 download_file->AnnotateWithSourceInformation(); |
| 371 #endif | 375 #endif |
| 372 | 376 |
| 373 BrowserThread::PostTask( | 377 BrowserThread::PostTask( |
| 374 BrowserThread::UI, FROM_HERE, | 378 BrowserThread::UI, FROM_HERE, |
| 375 base::Bind(&DownloadManager::OnDownloadRenamedToFinalName, | 379 base::Bind(&DownloadManagerInterface::OnDownloadRenamedToFinalName, |
| 376 download_manager, global_id.local(), new_path, uniquifier)); | 380 download_manager, global_id.local(), new_path, uniquifier)); |
| 377 } | 381 } |
| 378 | 382 |
| 379 // Called only from RenameInProgressDownloadFile and | 383 // Called only from RenameInProgressDownloadFile and |
| 380 // RenameCompletingDownloadFile on the FILE thread. | 384 // RenameCompletingDownloadFile on the FILE thread. |
| 381 void DownloadFileManager::CancelDownloadOnRename( | 385 void DownloadFileManager::CancelDownloadOnRename( |
| 382 DownloadId global_id, net::Error rename_error) { | 386 DownloadId global_id, net::Error rename_error) { |
| 383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 384 | 388 |
| 385 DownloadFile* download_file = GetDownloadFile(global_id); | 389 DownloadFile* download_file = GetDownloadFile(global_id); |
| 386 if (!download_file) | 390 if (!download_file) |
| 387 return; | 391 return; |
| 388 | 392 |
| 389 DownloadManager* download_manager = download_file->GetDownloadManager(); | 393 DownloadManagerInterface* download_manager = |
| 394 download_file->GetDownloadManager(); |
| 390 if (!download_manager) { | 395 if (!download_manager) { |
| 391 // Without a download manager, we can't cancel the request normally, so we | 396 // Without a download manager, we can't cancel the request normally, so we |
| 392 // need to do it here. The normal path will also update the download | 397 // need to do it here. The normal path will also update the download |
| 393 // history before canceling the request. | 398 // history before canceling the request. |
| 394 download_file->CancelDownloadRequest(); | 399 download_file->CancelDownloadRequest(); |
| 395 return; | 400 return; |
| 396 } | 401 } |
| 397 | 402 |
| 398 BrowserThread::PostTask( | 403 BrowserThread::PostTask( |
| 399 BrowserThread::UI, FROM_HERE, | 404 BrowserThread::UI, FROM_HERE, |
| 400 base::Bind(&DownloadManager::OnDownloadInterrupted, | 405 base::Bind(&DownloadManagerInterface::OnDownloadInterrupted, |
| 401 download_manager, global_id.local(), | 406 download_manager, global_id.local(), |
| 402 download_file->bytes_so_far(), | 407 download_file->bytes_so_far(), |
| 403 ConvertNetErrorToInterruptReason( | 408 ConvertNetErrorToInterruptReason( |
| 404 rename_error, DOWNLOAD_INTERRUPT_FROM_DISK))); | 409 rename_error, DOWNLOAD_INTERRUPT_FROM_DISK))); |
| 405 } | 410 } |
| 406 | 411 |
| 407 void DownloadFileManager::EraseDownload(DownloadId global_id) { | 412 void DownloadFileManager::EraseDownload(DownloadId global_id) { |
| 408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 409 | 414 |
| 410 if (!ContainsKey(downloads_, global_id)) | 415 if (!ContainsKey(downloads_, global_id)) |
| 411 return; | 416 return; |
| 412 | 417 |
| 413 DownloadFile* download_file = downloads_[global_id]; | 418 DownloadFile* download_file = downloads_[global_id]; |
| 414 | 419 |
| 415 VLOG(20) << " " << __FUNCTION__ << "()" | 420 VLOG(20) << " " << __FUNCTION__ << "()" |
| 416 << " id = " << global_id | 421 << " id = " << global_id |
| 417 << " download_file = " << download_file->DebugString(); | 422 << " download_file = " << download_file->DebugString(); |
| 418 | 423 |
| 419 downloads_.erase(global_id); | 424 downloads_.erase(global_id); |
| 420 | 425 |
| 421 delete download_file; | 426 delete download_file; |
| 422 | 427 |
| 423 if (downloads_.empty()) | 428 if (downloads_.empty()) |
| 424 StopUpdateTimer(); | 429 StopUpdateTimer(); |
| 425 } | 430 } |
| OLD | NEW |