| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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.h" | 5 #include "chrome/browser/download/download_file.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/path_service.h" | 8 #include "base/path_service.h" |
| 9 #include "base/stl_util-inl.h" | 9 #include "base/stl_util-inl.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "base/task.h" | 11 #include "base/task.h" |
| 12 #include "base/thread.h" | 12 #include "base/thread.h" |
| 13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 14 #include "chrome/browser/browser_process.h" | 14 #include "chrome/browser/chrome_thread.h" |
| 15 #include "chrome/browser/download/download_manager.h" | 15 #include "chrome/browser/download/download_manager.h" |
| 16 #include "chrome/browser/net/chrome_url_request_context.h" | 16 #include "chrome/browser/net/chrome_url_request_context.h" |
| 17 #include "chrome/browser/profile.h" | 17 #include "chrome/browser/profile.h" |
| 18 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" | 18 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" |
| 19 #include "chrome/browser/tab_contents/tab_util.h" | 19 #include "chrome/browser/tab_contents/tab_util.h" |
| 20 #include "chrome/browser/tab_contents/tab_contents.h" | 20 #include "chrome/browser/tab_contents/tab_contents.h" |
| 21 #include "chrome/common/chrome_paths.h" | 21 #include "chrome/common/chrome_paths.h" |
| 22 #include "chrome/common/platform_util.h" | 22 #include "chrome/common/platform_util.h" |
| 23 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
| 24 #include "net/base/io_buffer.h" | 24 #include "net/base/io_buffer.h" |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 #elif defined(OS_MACOSX) | 152 #elif defined(OS_MACOSX) |
| 153 file_metadata::AddQuarantineMetadataToFile(full_path_, source_url_, | 153 file_metadata::AddQuarantineMetadataToFile(full_path_, source_url_, |
| 154 referrer_url_); | 154 referrer_url_); |
| 155 file_metadata::AddOriginMetadataToFile(full_path_, source_url_, | 155 file_metadata::AddOriginMetadataToFile(full_path_, source_url_, |
| 156 referrer_url_); | 156 referrer_url_); |
| 157 #endif | 157 #endif |
| 158 } | 158 } |
| 159 | 159 |
| 160 // DownloadFileManager implementation ------------------------------------------ | 160 // DownloadFileManager implementation ------------------------------------------ |
| 161 | 161 |
| 162 DownloadFileManager::DownloadFileManager(MessageLoop* ui_loop, | 162 DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh) |
| 163 ResourceDispatcherHost* rdh) | |
| 164 : next_id_(0), | 163 : next_id_(0), |
| 165 ui_loop_(ui_loop), | |
| 166 file_loop_(NULL), | |
| 167 io_loop_(NULL), | |
| 168 resource_dispatcher_host_(rdh) { | 164 resource_dispatcher_host_(rdh) { |
| 169 } | 165 } |
| 170 | 166 |
| 171 DownloadFileManager::~DownloadFileManager() { | 167 DownloadFileManager::~DownloadFileManager() { |
| 172 // Check for clean shutdown. | 168 // Check for clean shutdown. |
| 173 DCHECK(downloads_.empty()); | 169 DCHECK(downloads_.empty()); |
| 174 ui_progress_.clear(); | 170 ui_progress_.clear(); |
| 175 } | 171 } |
| 176 | 172 |
| 177 void DownloadFileManager::Initialize() { | |
| 178 io_loop_ = g_browser_process->io_thread()->message_loop(); | |
| 179 file_loop_ = g_browser_process->file_thread()->message_loop(); | |
| 180 } | |
| 181 | |
| 182 // Called during the browser shutdown process to clean up any state (open files, | 173 // Called during the browser shutdown process to clean up any state (open files, |
| 183 // timers) that live on the download_thread_. | 174 // timers) that live on the download_thread_. |
| 184 void DownloadFileManager::Shutdown() { | 175 void DownloadFileManager::Shutdown() { |
| 185 DCHECK(MessageLoop::current() == ui_loop_); | 176 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 186 StopUpdateTimer(); | 177 StopUpdateTimer(); |
| 187 file_loop_->PostTask(FROM_HERE, | 178 ChromeThread::PostTask( |
| 188 NewRunnableMethod(this, | 179 ChromeThread::FILE, FROM_HERE, |
| 189 &DownloadFileManager::OnShutdown)); | 180 NewRunnableMethod(this, &DownloadFileManager::OnShutdown)); |
| 190 } | 181 } |
| 191 | 182 |
| 192 // Cease download thread operations. | 183 // Cease download thread operations. |
| 193 void DownloadFileManager::OnShutdown() { | 184 void DownloadFileManager::OnShutdown() { |
| 194 DCHECK(MessageLoop::current() == file_loop_); | 185 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 195 // Delete any partial downloads during shutdown. | 186 // Delete any partial downloads during shutdown. |
| 196 for (DownloadFileMap::iterator it = downloads_.begin(); | 187 for (DownloadFileMap::iterator it = downloads_.begin(); |
| 197 it != downloads_.end(); ++it) { | 188 it != downloads_.end(); ++it) { |
| 198 DownloadFile* download = it->second; | 189 DownloadFile* download = it->second; |
| 199 if (download->in_progress()) | 190 if (download->in_progress()) |
| 200 download->Cancel(); | 191 download->Cancel(); |
| 201 delete download; | 192 delete download; |
| 202 } | 193 } |
| 203 downloads_.clear(); | 194 downloads_.clear(); |
| 204 } | 195 } |
| 205 | 196 |
| 206 // Lookup one in-progress download. | 197 // Lookup one in-progress download. |
| 207 DownloadFile* DownloadFileManager::LookupDownload(int id) { | 198 DownloadFile* DownloadFileManager::LookupDownload(int id) { |
| 208 DownloadFileMap::iterator it = downloads_.find(id); | 199 DownloadFileMap::iterator it = downloads_.find(id); |
| 209 return it == downloads_.end() ? NULL : it->second; | 200 return it == downloads_.end() ? NULL : it->second; |
| 210 } | 201 } |
| 211 | 202 |
| 212 // The UI progress is updated on the file thread and removed on the UI thread. | 203 // The UI progress is updated on the file thread and removed on the UI thread. |
| 213 void DownloadFileManager::RemoveDownloadFromUIProgress(int id) { | 204 void DownloadFileManager::RemoveDownloadFromUIProgress(int id) { |
| 214 DCHECK(MessageLoop::current() == ui_loop_); | 205 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 215 AutoLock lock(progress_lock_); | 206 AutoLock lock(progress_lock_); |
| 216 if (ui_progress_.find(id) != ui_progress_.end()) | 207 if (ui_progress_.find(id) != ui_progress_.end()) |
| 217 ui_progress_.erase(id); | 208 ui_progress_.erase(id); |
| 218 } | 209 } |
| 219 | 210 |
| 220 // Throttle updates to the UI thread by only posting update notifications at a | 211 // Throttle updates to the UI thread by only posting update notifications at a |
| 221 // regularly controlled interval. | 212 // regularly controlled interval. |
| 222 void DownloadFileManager::StartUpdateTimer() { | 213 void DownloadFileManager::StartUpdateTimer() { |
| 223 DCHECK(MessageLoop::current() == ui_loop_); | 214 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 224 if (!update_timer_.IsRunning()) { | 215 if (!update_timer_.IsRunning()) { |
| 225 update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), | 216 update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), |
| 226 this, &DownloadFileManager::UpdateInProgressDownloads); | 217 this, &DownloadFileManager::UpdateInProgressDownloads); |
| 227 } | 218 } |
| 228 } | 219 } |
| 229 | 220 |
| 230 void DownloadFileManager::StopUpdateTimer() { | 221 void DownloadFileManager::StopUpdateTimer() { |
| 231 DCHECK(MessageLoop::current() == ui_loop_); | 222 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 232 update_timer_.Stop(); | 223 update_timer_.Stop(); |
| 233 } | 224 } |
| 234 | 225 |
| 235 // Called on the IO thread once the ResourceDispatcherHost has decided that a | 226 // Called on the IO thread once the ResourceDispatcherHost has decided that a |
| 236 // request is a download. | 227 // request is a download. |
| 237 int DownloadFileManager::GetNextId() { | 228 int DownloadFileManager::GetNextId() { |
| 238 DCHECK(MessageLoop::current() == io_loop_); | 229 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 239 return next_id_++; | 230 return next_id_++; |
| 240 } | 231 } |
| 241 | 232 |
| 242 // Notifications sent from the IO thread and run on the download thread: | 233 // Notifications sent from the IO thread and run on the download thread: |
| 243 | 234 |
| 244 // The IO thread created 'info', but the download thread (this method) uses it | 235 // The IO thread created 'info', but the download thread (this method) uses it |
| 245 // to create a DownloadFile, then passes 'info' to the UI thread where it is | 236 // to create a DownloadFile, then passes 'info' to the UI thread where it is |
| 246 // finally consumed and deleted. | 237 // finally consumed and deleted. |
| 247 void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { | 238 void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { |
| 248 DCHECK(MessageLoop::current() == file_loop_); | 239 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 249 DCHECK(info); | 240 DCHECK(info); |
| 250 | 241 |
| 251 DownloadFile* download = new DownloadFile(info); | 242 DownloadFile* download = new DownloadFile(info); |
| 252 if (!download->Initialize()) { | 243 if (!download->Initialize()) { |
| 253 // Couldn't open, cancel the operation. The UI thread does not yet know | 244 // Couldn't open, cancel the operation. The UI thread does not yet know |
| 254 // about this download so we have to clean up 'info'. We need to get back | 245 // about this download so we have to clean up 'info'. We need to get back |
| 255 // to the IO thread to cancel the network request and CancelDownloadRequest | 246 // to the IO thread to cancel the network request and CancelDownloadRequest |
| 256 // on the UI thread is the safe way to do that. | 247 // on the UI thread is the safe way to do that. |
| 257 ChromeThread::PostTask( | 248 ChromeThread::PostTask( |
| 258 ChromeThread::IO, FROM_HERE, | 249 ChromeThread::IO, FROM_HERE, |
| 259 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, | 250 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, |
| 260 resource_dispatcher_host_, | 251 resource_dispatcher_host_, |
| 261 info->child_id, | 252 info->child_id, |
| 262 info->request_id)); | 253 info->request_id)); |
| 263 delete info; | 254 delete info; |
| 264 delete download; | 255 delete download; |
| 265 return; | 256 return; |
| 266 } | 257 } |
| 267 | 258 |
| 268 DCHECK(LookupDownload(info->download_id) == NULL); | 259 DCHECK(LookupDownload(info->download_id) == NULL); |
| 269 downloads_[info->download_id] = download; | 260 downloads_[info->download_id] = download; |
| 270 info->path = download->full_path(); | 261 info->path = download->full_path(); |
| 271 { | 262 { |
| 272 AutoLock lock(progress_lock_); | 263 AutoLock lock(progress_lock_); |
| 273 ui_progress_[info->download_id] = info->received_bytes; | 264 ui_progress_[info->download_id] = info->received_bytes; |
| 274 } | 265 } |
| 275 | 266 |
| 276 ui_loop_->PostTask(FROM_HERE, | 267 ChromeThread::PostTask( |
| 277 NewRunnableMethod(this, | 268 ChromeThread::UI, FROM_HERE, |
| 278 &DownloadFileManager::OnStartDownload, | 269 NewRunnableMethod(this, &DownloadFileManager::OnStartDownload, info)); |
| 279 info)); | |
| 280 } | 270 } |
| 281 | 271 |
| 282 // We don't forward an update to the UI thread here, since we want to throttle | 272 // We don't forward an update to the UI thread here, since we want to throttle |
| 283 // the UI update rate via a periodic timer. If the user has cancelled the | 273 // the UI update rate via a periodic timer. If the user has cancelled the |
| 284 // download (in the UI thread), we may receive a few more updates before the IO | 274 // download (in the UI thread), we may receive a few more updates before the IO |
| 285 // thread gets the cancel message: we just delete the data since the | 275 // thread gets the cancel message: we just delete the data since the |
| 286 // DownloadFile has been deleted. | 276 // DownloadFile has been deleted. |
| 287 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { | 277 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { |
| 288 DCHECK(MessageLoop::current() == file_loop_); | 278 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 289 std::vector<DownloadBuffer::Contents> contents; | 279 std::vector<DownloadBuffer::Contents> contents; |
| 290 { | 280 { |
| 291 AutoLock auto_lock(buffer->lock); | 281 AutoLock auto_lock(buffer->lock); |
| 292 contents.swap(buffer->contents); | 282 contents.swap(buffer->contents); |
| 293 } | 283 } |
| 294 | 284 |
| 295 DownloadFile* download = LookupDownload(id); | 285 DownloadFile* download = LookupDownload(id); |
| 296 for (size_t i = 0; i < contents.size(); ++i) { | 286 for (size_t i = 0; i < contents.size(); ++i) { |
| 297 net::IOBuffer* data = contents[i].first; | 287 net::IOBuffer* data = contents[i].first; |
| 298 const int data_len = contents[i].second; | 288 const int data_len = contents[i].second; |
| 299 if (download) | 289 if (download) |
| 300 download->AppendDataToFile(data->data(), data_len); | 290 download->AppendDataToFile(data->data(), data_len); |
| 301 data->Release(); | 291 data->Release(); |
| 302 } | 292 } |
| 303 | 293 |
| 304 if (download) { | 294 if (download) { |
| 305 AutoLock lock(progress_lock_); | 295 AutoLock lock(progress_lock_); |
| 306 ui_progress_[download->id()] = download->bytes_so_far(); | 296 ui_progress_[download->id()] = download->bytes_so_far(); |
| 307 } | 297 } |
| 308 } | 298 } |
| 309 | 299 |
| 310 void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) { | 300 void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) { |
| 311 DCHECK(MessageLoop::current() == file_loop_); | 301 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 312 delete buffer; | 302 delete buffer; |
| 313 DownloadFileMap::iterator it = downloads_.find(id); | 303 DownloadFileMap::iterator it = downloads_.find(id); |
| 314 if (it != downloads_.end()) { | 304 if (it != downloads_.end()) { |
| 315 DownloadFile* download = it->second; | 305 DownloadFile* download = it->second; |
| 316 download->set_in_progress(false); | 306 download->set_in_progress(false); |
| 317 | 307 |
| 318 ui_loop_->PostTask(FROM_HERE, | 308 ChromeThread::PostTask( |
| 319 NewRunnableMethod(this, | 309 ChromeThread::UI, FROM_HERE, |
| 320 &DownloadFileManager::OnDownloadFinished, | 310 NewRunnableMethod( |
| 321 id, | 311 this, &DownloadFileManager::OnDownloadFinished, |
| 322 download->bytes_so_far())); | 312 id, download->bytes_so_far())); |
| 323 | 313 |
| 324 // We need to keep the download around until the UI thread has finalized | 314 // We need to keep the download around until the UI thread has finalized |
| 325 // the name. | 315 // the name. |
| 326 if (download->path_renamed()) { | 316 if (download->path_renamed()) { |
| 327 downloads_.erase(it); | 317 downloads_.erase(it); |
| 328 delete download; | 318 delete download; |
| 329 } | 319 } |
| 330 } | 320 } |
| 331 | 321 |
| 332 if (downloads_.empty()) | 322 if (downloads_.empty()) |
| 333 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 323 ChromeThread::PostTask( |
| 334 this, &DownloadFileManager::StopUpdateTimer)); | 324 ChromeThread::UI, FROM_HERE, |
| 325 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); |
| 335 } | 326 } |
| 336 | 327 |
| 337 // This method will be sent via a user action, or shutdown on the UI thread, and | 328 // This method will be sent via a user action, or shutdown on the UI thread, and |
| 338 // run on the download thread. Since this message has been sent from the UI | 329 // run on the download thread. Since this message has been sent from the UI |
| 339 // thread, the download may have already completed and won't exist in our map. | 330 // thread, the download may have already completed and won't exist in our map. |
| 340 void DownloadFileManager::CancelDownload(int id) { | 331 void DownloadFileManager::CancelDownload(int id) { |
| 341 DCHECK(MessageLoop::current() == file_loop_); | 332 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 342 DownloadFileMap::iterator it = downloads_.find(id); | 333 DownloadFileMap::iterator it = downloads_.find(id); |
| 343 if (it != downloads_.end()) { | 334 if (it != downloads_.end()) { |
| 344 DownloadFile* download = it->second; | 335 DownloadFile* download = it->second; |
| 345 download->set_in_progress(false); | 336 download->set_in_progress(false); |
| 346 | 337 |
| 347 download->Cancel(); | 338 download->Cancel(); |
| 348 | 339 |
| 349 ui_loop_->PostTask(FROM_HERE, | 340 ChromeThread::PostTask( |
| 350 NewRunnableMethod(this, | 341 ChromeThread::UI, FROM_HERE, |
| 351 &DownloadFileManager::RemoveDownloadFromUIProgress, | 342 NewRunnableMethod( |
| 352 download->id())); | 343 this, &DownloadFileManager::RemoveDownloadFromUIProgress, |
| 344 download->id())); |
| 353 | 345 |
| 354 if (download->path_renamed()) { | 346 if (download->path_renamed()) { |
| 355 downloads_.erase(it); | 347 downloads_.erase(it); |
| 356 delete download; | 348 delete download; |
| 357 } | 349 } |
| 358 } | 350 } |
| 359 | 351 |
| 360 if (downloads_.empty()) | 352 if (downloads_.empty()) { |
| 361 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 353 ChromeThread::PostTask( |
| 362 this, &DownloadFileManager::StopUpdateTimer)); | 354 ChromeThread::UI, FROM_HERE, |
| 355 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); |
| 356 } |
| 363 } | 357 } |
| 364 | 358 |
| 365 // Our periodic timer has fired so send the UI thread updates on all in progress | 359 // Our periodic timer has fired so send the UI thread updates on all in progress |
| 366 // downloads. | 360 // downloads. |
| 367 void DownloadFileManager::UpdateInProgressDownloads() { | 361 void DownloadFileManager::UpdateInProgressDownloads() { |
| 368 DCHECK(MessageLoop::current() == ui_loop_); | 362 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 369 AutoLock lock(progress_lock_); | 363 AutoLock lock(progress_lock_); |
| 370 ProgressMap::iterator it = ui_progress_.begin(); | 364 ProgressMap::iterator it = ui_progress_.begin(); |
| 371 for (; it != ui_progress_.end(); ++it) { | 365 for (; it != ui_progress_.end(); ++it) { |
| 372 const int id = it->first; | 366 const int id = it->first; |
| 373 DownloadManager* manager = LookupManager(id); | 367 DownloadManager* manager = LookupManager(id); |
| 374 if (manager) | 368 if (manager) |
| 375 manager->UpdateDownload(id, it->second); | 369 manager->UpdateDownload(id, it->second); |
| 376 } | 370 } |
| 377 } | 371 } |
| 378 | 372 |
| 379 // Notifications sent from the download thread and run on the UI thread. | 373 // Notifications sent from the download thread and run on the UI thread. |
| 380 | 374 |
| 381 // Lookup the DownloadManager for this TabContents' profile and inform it of | 375 // Lookup the DownloadManager for this TabContents' profile and inform it of |
| 382 // a new download. | 376 // a new download. |
| 383 // TODO(paulg): When implementing download restart via the Downloads tab, | 377 // TODO(paulg): When implementing download restart via the Downloads tab, |
| 384 // there will be no 'render_process_id' or 'render_view_id'. | 378 // there will be no 'render_process_id' or 'render_view_id'. |
| 385 void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) { | 379 void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) { |
| 386 DCHECK(MessageLoop::current() == ui_loop_); | 380 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 387 DownloadManager* manager = DownloadManagerFromRenderIds(info->child_id, | 381 DownloadManager* manager = DownloadManagerFromRenderIds(info->child_id, |
| 388 info->render_view_id); | 382 info->render_view_id); |
| 389 if (!manager) { | 383 if (!manager) { |
| 390 ChromeThread::PostTask( | 384 ChromeThread::PostTask( |
| 391 ChromeThread::IO, FROM_HERE, | 385 ChromeThread::IO, FROM_HERE, |
| 392 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, | 386 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, |
| 393 resource_dispatcher_host_, | 387 resource_dispatcher_host_, |
| 394 info->child_id, | 388 info->child_id, |
| 395 info->request_id)); | 389 info->request_id)); |
| 396 delete info; | 390 delete info; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 416 NOTREACHED(); | 410 NOTREACHED(); |
| 417 | 411 |
| 418 // StartDownload will clean up |info|. | 412 // StartDownload will clean up |info|. |
| 419 manager->StartDownload(info); | 413 manager->StartDownload(info); |
| 420 } | 414 } |
| 421 | 415 |
| 422 // Update the Download Manager with the finish state, and remove the request | 416 // Update the Download Manager with the finish state, and remove the request |
| 423 // tracking entries. | 417 // tracking entries. |
| 424 void DownloadFileManager::OnDownloadFinished(int id, | 418 void DownloadFileManager::OnDownloadFinished(int id, |
| 425 int64 bytes_so_far) { | 419 int64 bytes_so_far) { |
| 426 DCHECK(MessageLoop::current() == ui_loop_); | 420 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 427 DownloadManager* manager = LookupManager(id); | 421 DownloadManager* manager = LookupManager(id); |
| 428 if (manager) | 422 if (manager) |
| 429 manager->DownloadFinished(id, bytes_so_far); | 423 manager->DownloadFinished(id, bytes_so_far); |
| 430 RemoveDownload(id, manager); | 424 RemoveDownload(id, manager); |
| 431 RemoveDownloadFromUIProgress(id); | 425 RemoveDownloadFromUIProgress(id); |
| 432 } | 426 } |
| 433 | 427 |
| 434 void DownloadFileManager::DownloadUrl( | 428 void DownloadFileManager::DownloadUrl( |
| 435 const GURL& url, | 429 const GURL& url, |
| 436 const GURL& referrer, | 430 const GURL& referrer, |
| 437 const std::string& referrer_charset, | 431 const std::string& referrer_charset, |
| 438 int render_process_host_id, | 432 int render_process_host_id, |
| 439 int render_view_id, | 433 int render_view_id, |
| 440 URLRequestContextGetter* request_context_getter) { | 434 URLRequestContextGetter* request_context_getter) { |
| 441 DCHECK(MessageLoop::current() == ui_loop_); | 435 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 442 base::Thread* thread = g_browser_process->io_thread(); | 436 ChromeThread::PostTask( |
| 443 if (thread) { | 437 ChromeThread::IO, FROM_HERE, |
| 444 thread->message_loop()->PostTask(FROM_HERE, | |
| 445 NewRunnableMethod(this, | 438 NewRunnableMethod(this, |
| 446 &DownloadFileManager::OnDownloadUrl, | 439 &DownloadFileManager::OnDownloadUrl, |
| 447 url, | 440 url, |
| 448 referrer, | 441 referrer, |
| 449 referrer_charset, | 442 referrer_charset, |
| 450 render_process_host_id, | 443 render_process_host_id, |
| 451 render_view_id, | 444 render_view_id, |
| 452 request_context_getter)); | 445 request_context_getter)); |
| 453 } | |
| 454 } | 446 } |
| 455 | 447 |
| 456 // Relate a download ID to its owning DownloadManager. | 448 // Relate a download ID to its owning DownloadManager. |
| 457 DownloadManager* DownloadFileManager::LookupManager(int download_id) { | 449 DownloadManager* DownloadFileManager::LookupManager(int download_id) { |
| 458 DCHECK(MessageLoop::current() == ui_loop_); | 450 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 459 DownloadManagerMap::iterator it = managers_.find(download_id); | 451 DownloadManagerMap::iterator it = managers_.find(download_id); |
| 460 if (it != managers_.end()) | 452 if (it != managers_.end()) |
| 461 return it->second; | 453 return it->second; |
| 462 return NULL; | 454 return NULL; |
| 463 } | 455 } |
| 464 | 456 |
| 465 // Utility function for look up table maintenance, called on the UI thread. | 457 // Utility function for look up table maintenance, called on the UI thread. |
| 466 // A manager may have multiple downloads in progress, so we just look up the | 458 // A manager may have multiple downloads in progress, so we just look up the |
| 467 // one download (id) and remove it from the set, and remove the set if it | 459 // one download (id) and remove it from the set, and remove the set if it |
| 468 // becomes empty. | 460 // becomes empty. |
| 469 void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) { | 461 void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) { |
| 470 DCHECK(MessageLoop::current() == ui_loop_); | 462 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 471 if (manager) { | 463 if (manager) { |
| 472 RequestMap::iterator it = requests_.find(manager); | 464 RequestMap::iterator it = requests_.find(manager); |
| 473 if (it != requests_.end()) { | 465 if (it != requests_.end()) { |
| 474 DownloadRequests& downloads = it->second; | 466 DownloadRequests& downloads = it->second; |
| 475 DownloadRequests::iterator rit = downloads.find(id); | 467 DownloadRequests::iterator rit = downloads.find(id); |
| 476 if (rit != downloads.end()) | 468 if (rit != downloads.end()) |
| 477 downloads.erase(rit); | 469 downloads.erase(rit); |
| 478 if (downloads.empty()) | 470 if (downloads.empty()) |
| 479 requests_.erase(it); | 471 requests_.erase(it); |
| 480 } | 472 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 498 Profile* profile = contents->profile(); | 490 Profile* profile = contents->profile(); |
| 499 if (profile) | 491 if (profile) |
| 500 return profile->GetDownloadManager(); | 492 return profile->GetDownloadManager(); |
| 501 } | 493 } |
| 502 | 494 |
| 503 return NULL; | 495 return NULL; |
| 504 } | 496 } |
| 505 | 497 |
| 506 // Called by DownloadManagers in their destructor, and only on the UI thread. | 498 // Called by DownloadManagers in their destructor, and only on the UI thread. |
| 507 void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) { | 499 void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) { |
| 508 DCHECK(MessageLoop::current() == ui_loop_); | 500 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 509 DCHECK(manager); | 501 DCHECK(manager); |
| 510 RequestMap::iterator it = requests_.find(manager); | 502 RequestMap::iterator it = requests_.find(manager); |
| 511 if (it == requests_.end()) | 503 if (it == requests_.end()) |
| 512 return; | 504 return; |
| 513 | 505 |
| 514 const DownloadRequests& requests = it->second; | 506 const DownloadRequests& requests = it->second; |
| 515 DownloadRequests::const_iterator i = requests.begin(); | 507 DownloadRequests::const_iterator i = requests.begin(); |
| 516 for (; i != requests.end(); ++i) { | 508 for (; i != requests.end(); ++i) { |
| 517 DownloadManagerMap::iterator dit = managers_.find(*i); | 509 DownloadManagerMap::iterator dit = managers_.find(*i); |
| 518 if (dit != managers_.end()) { | 510 if (dit != managers_.end()) { |
| 519 DCHECK(dit->second == manager); | 511 DCHECK(dit->second == manager); |
| 520 managers_.erase(dit); | 512 managers_.erase(dit); |
| 521 } | 513 } |
| 522 } | 514 } |
| 523 | 515 |
| 524 requests_.erase(it); | 516 requests_.erase(it); |
| 525 } | 517 } |
| 526 | 518 |
| 527 | 519 |
| 528 // Notifications from the UI thread and run on the IO thread | 520 // Notifications from the UI thread and run on the IO thread |
| 529 | 521 |
| 530 // Initiate a request for URL to be downloaded. | 522 // Initiate a request for URL to be downloaded. |
| 531 void DownloadFileManager::OnDownloadUrl( | 523 void DownloadFileManager::OnDownloadUrl( |
| 532 const GURL& url, | 524 const GURL& url, |
| 533 const GURL& referrer, | 525 const GURL& referrer, |
| 534 const std::string& referrer_charset, | 526 const std::string& referrer_charset, |
| 535 int render_process_host_id, | 527 int render_process_host_id, |
| 536 int render_view_id, | 528 int render_view_id, |
| 537 URLRequestContextGetter* request_context_getter) { | 529 URLRequestContextGetter* request_context_getter) { |
| 538 DCHECK(MessageLoop::current() == io_loop_); | 530 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 539 | 531 |
| 540 URLRequestContext* context = request_context_getter->GetURLRequestContext(); | 532 URLRequestContext* context = request_context_getter->GetURLRequestContext(); |
| 541 context->set_referrer_charset(referrer_charset); | 533 context->set_referrer_charset(referrer_charset); |
| 542 | 534 |
| 543 resource_dispatcher_host_->BeginDownload(url, | 535 resource_dispatcher_host_->BeginDownload(url, |
| 544 referrer, | 536 referrer, |
| 545 render_process_host_id, | 537 render_process_host_id, |
| 546 render_view_id, | 538 render_view_id, |
| 547 context); | 539 context); |
| 548 } | 540 } |
| 549 | 541 |
| 550 // Actions from the UI thread and run on the download thread | 542 // Actions from the UI thread and run on the download thread |
| 551 | 543 |
| 552 // Open a download, or show it in a file explorer window. We run on this | 544 // Open a download, or show it in a file explorer window. We run on this |
| 553 // thread to avoid blocking the UI with (potentially) slow Shell operations. | 545 // thread to avoid blocking the UI with (potentially) slow Shell operations. |
| 554 // TODO(paulg): File 'stat' operations. | 546 // TODO(paulg): File 'stat' operations. |
| 555 #if !defined(OS_MACOSX) | 547 #if !defined(OS_MACOSX) |
| 556 void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) { | 548 void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) { |
| 557 DCHECK(MessageLoop::current() == file_loop_); | 549 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 558 platform_util::ShowItemInFolder(full_path); | 550 platform_util::ShowItemInFolder(full_path); |
| 559 } | 551 } |
| 560 #endif | 552 #endif |
| 561 | 553 |
| 562 // Launches the selected download using ShellExecute 'open' verb. For windows, | 554 // Launches the selected download using ShellExecute 'open' verb. For windows, |
| 563 // if there is a valid parent window, the 'safer' version will be used which can | 555 // if there is a valid parent window, the 'safer' version will be used which can |
| 564 // display a modal dialog asking for user consent on dangerous files. | 556 // display a modal dialog asking for user consent on dangerous files. |
| 565 #if !defined(OS_MACOSX) | 557 #if !defined(OS_MACOSX) |
| 566 void DownloadFileManager::OnOpenDownloadInShell(const FilePath& full_path, | 558 void DownloadFileManager::OnOpenDownloadInShell(const FilePath& full_path, |
| 567 const GURL& url, | 559 const GURL& url, |
| 568 gfx::NativeView parent_window) { | 560 gfx::NativeView parent_window) { |
| 569 DCHECK(MessageLoop::current() == file_loop_); | 561 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 570 #if defined(OS_WIN) | 562 #if defined(OS_WIN) |
| 571 if (NULL != parent_window) { | 563 if (NULL != parent_window) { |
| 572 win_util::SaferOpenItemViaShell(parent_window, L"", full_path, | 564 win_util::SaferOpenItemViaShell(parent_window, L"", full_path, |
| 573 UTF8ToWide(url.spec())); | 565 UTF8ToWide(url.spec())); |
| 574 return; | 566 return; |
| 575 } | 567 } |
| 576 #endif | 568 #endif |
| 577 platform_util::OpenItem(full_path); | 569 platform_util::OpenItem(full_path); |
| 578 } | 570 } |
| 579 #endif // OS_MACOSX | 571 #endif // OS_MACOSX |
| 580 | 572 |
| 581 // The DownloadManager in the UI thread has provided a final name for the | 573 // The DownloadManager in the UI thread has provided a final name for the |
| 582 // download specified by 'id'. Rename the in progress download, and remove it | 574 // download specified by 'id'. Rename the in progress download, and remove it |
| 583 // from our table if it has been completed or cancelled already. | 575 // from our table if it has been completed or cancelled already. |
| 584 void DownloadFileManager::OnFinalDownloadName(int id, | 576 void DownloadFileManager::OnFinalDownloadName(int id, |
| 585 const FilePath& full_path, | 577 const FilePath& full_path, |
| 586 DownloadManager* manager) { | 578 DownloadManager* manager) { |
| 587 DCHECK(MessageLoop::current() == file_loop_); | 579 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 588 DownloadFileMap::iterator it = downloads_.find(id); | 580 DownloadFileMap::iterator it = downloads_.find(id); |
| 589 if (it == downloads_.end()) | 581 if (it == downloads_.end()) |
| 590 return; | 582 return; |
| 591 | 583 |
| 592 file_util::CreateDirectory(full_path.DirName()); | 584 file_util::CreateDirectory(full_path.DirName()); |
| 593 | 585 |
| 594 DownloadFile* download = it->second; | 586 DownloadFile* download = it->second; |
| 595 if (download->Rename(full_path)) { | 587 if (download->Rename(full_path)) { |
| 596 #if defined(OS_MACOSX) | 588 #if defined(OS_MACOSX) |
| 597 // Done here because we only want to do this once; see | 589 // Done here because we only want to do this once; see |
| 598 // http://crbug.com/13120 for details. | 590 // http://crbug.com/13120 for details. |
| 599 download->AnnotateWithSourceInformation(); | 591 download->AnnotateWithSourceInformation(); |
| 600 #endif | 592 #endif |
| 601 ui_loop_->PostTask(FROM_HERE, | 593 ChromeThread::PostTask( |
| 602 NewRunnableMethod(manager, | 594 ChromeThread::UI, FROM_HERE, |
| 603 &DownloadManager::DownloadRenamedToFinalName, | 595 NewRunnableMethod( |
| 604 id, | 596 manager, &DownloadManager::DownloadRenamedToFinalName, id, |
| 605 full_path)); | 597 full_path)); |
| 606 } else { | 598 } else { |
| 607 // Error. Between the time the UI thread generated 'full_path' to the time | 599 // Error. Between the time the UI thread generated 'full_path' to the time |
| 608 // this code runs, something happened that prevents us from renaming. | 600 // this code runs, something happened that prevents us from renaming. |
| 609 DownloadManagerMap::iterator dmit = managers_.find(download->id()); | 601 DownloadManagerMap::iterator dmit = managers_.find(download->id()); |
| 610 if (dmit != managers_.end()) { | 602 if (dmit != managers_.end()) { |
| 611 DownloadManager* dlm = dmit->second; | 603 DownloadManager* dlm = dmit->second; |
| 612 ui_loop_->PostTask(FROM_HERE, | 604 ChromeThread::PostTask( |
| 613 NewRunnableMethod(dlm, | 605 ChromeThread::UI, FROM_HERE, |
| 614 &DownloadManager::DownloadCancelled, | 606 NewRunnableMethod(dlm, &DownloadManager::DownloadCancelled, id)); |
| 615 id)); | |
| 616 } else { | 607 } else { |
| 617 ChromeThread::PostTask( | 608 ChromeThread::PostTask( |
| 618 ChromeThread::IO, FROM_HERE, | 609 ChromeThread::IO, FROM_HERE, |
| 619 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, | 610 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, |
| 620 resource_dispatcher_host_, | 611 resource_dispatcher_host_, |
| 621 download->child_id(), | 612 download->child_id(), |
| 622 download->request_id())); | 613 download->request_id())); |
| 623 } | 614 } |
| 624 } | 615 } |
| 625 | 616 |
| 626 // If the download has completed before we got this final name, we remove it | 617 // If the download has completed before we got this final name, we remove it |
| 627 // from our in progress map. | 618 // from our in progress map. |
| 628 if (!download->in_progress()) { | 619 if (!download->in_progress()) { |
| 629 downloads_.erase(it); | 620 downloads_.erase(it); |
| 630 delete download; | 621 delete download; |
| 631 } | 622 } |
| 632 | 623 |
| 633 if (downloads_.empty()) | 624 if (downloads_.empty()) { |
| 634 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 625 ChromeThread::PostTask( |
| 635 this, &DownloadFileManager::StopUpdateTimer)); | 626 ChromeThread::UI, FROM_HERE, |
| 627 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); |
| 628 } |
| 636 } | 629 } |
| 637 | 630 |
| 638 // static | 631 // static |
| 639 void DownloadFileManager::DeleteFile(const FilePath& path) { | 632 void DownloadFileManager::DeleteFile(const FilePath& path) { |
| 640 // Make sure we only delete files. | 633 // Make sure we only delete files. |
| 641 if (!file_util::DirectoryExists(path)) | 634 if (!file_util::DirectoryExists(path)) |
| 642 file_util::Delete(path, false); | 635 file_util::Delete(path, false); |
| 643 } | 636 } |
| OLD | NEW |