download_file_manager.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_file_manager.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stl_util-inl.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chrome_thread.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_manager.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_util.h" 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/history/download_create_info.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/chrome_url_request_context.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/platform_util.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/resource_dispatcher_host.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_util.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h" 233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/io_buffer.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/win_util.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/win_safe_util.h" 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_MACOSX) 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/cocoa/file_metadata.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Throttle updates to the UI thread so that a fast moving download doesn't 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// cause it to become unresponsive (in milliseconds). 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kUpdatePeriodMs = 500; 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 383345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickDownloadManager* DownloadManagerForRenderViewHost(int render_process_id, 393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int render_view_id) { 403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick TabContents* contents = tab_util::GetTabContentsByID(render_process_id, 433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick render_view_id); 443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (contents) { 453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Profile* profile = contents->profile(); 463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (profile) 473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return profile->GetDownloadManager(); 483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return NULL; 513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh) 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : next_id_(0), 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resource_dispatcher_host_(rdh) { 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadFileManager::~DownloadFileManager() { 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(downloads_.empty()); 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::Shutdown() { 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::PostTask( 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::FILE, FROM_HERE, 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &DownloadFileManager::OnShutdown)); 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::OnShutdown() { 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick StopUpdateTimer(); 743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick STLDeleteValues(&downloads_); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DownloadFileManager::CreateDownloadFile( 783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadCreateInfo* info, DownloadManager* download_manager) { 793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick scoped_ptr<DownloadFile> download_file( 823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick new DownloadFile(info, download_manager)); 833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!download_file->Initialize()) { 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::PostTask( 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::IO, FROM_HERE, 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableFunction(&download_util::CancelDownloadRequest, 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resource_dispatcher_host_, 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->child_id, 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->request_id)); 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete info; 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(GetDownloadFile(info->download_id) == NULL); 953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick downloads_[info->download_id] = download_file.release(); 963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // TODO(phajdan.jr): fix the duplication of path info below. 973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick info->path = info->save_info.file_path; 983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The file is now ready, we can un-pause the request and start saving data. 1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::PostTask( 1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::IO, FROM_HERE, 1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NewRunnableMethod(this, &DownloadFileManager::ResumeDownloadRequest, 1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick info->child_id, info->request_id)); 1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartUpdateTimer(); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::PostTask( 1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::UI, FROM_HERE, 1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NewRunnableMethod(download_manager, 1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick &DownloadManager::StartDownload, info)); 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DownloadFileManager::ResumeDownloadRequest(int child_id, int request_id) { 1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // This balances the pause in DownloadResourceHandler::OnResponseStarted. 1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick resource_dispatcher_host_->PauseRequest(child_id, request_id, false); 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadFile* DownloadFileManager::GetDownloadFile(int id) { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadFileMap::iterator it = downloads_.find(id); 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return it == downloads_.end() ? NULL : it->second; 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::StartUpdateTimer() { 1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!update_timer_.IsRunning()) { 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, &DownloadFileManager::UpdateInProgressDownloads); 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::StopUpdateTimer() { 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch update_timer_.Stop(); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::UpdateInProgressDownloads() { 1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (DownloadFileMap::iterator i = downloads_.begin(); 1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick i != downloads_.end(); ++i) { 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int id = i->first; 1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadFile* download_file = i->second; 1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadManager* manager = download_file->GetDownloadManager(); 1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (manager) { 1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, 1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NewRunnableMethod(manager, &DownloadManager::UpdateDownload, 1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick id, download_file->bytes_so_far())); 1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called on the IO thread once the ResourceDispatcherHost has decided that a 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// request is a download. 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint DownloadFileManager::GetNextId() { 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return next_id_++; 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::StartDownload(DownloadCreateInfo* info) { 1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(info); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadManager* manager = DownloadManagerForRenderViewHost( 1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick info->child_id, info->render_view_id); 1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!manager) { 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::PostTask( 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::IO, FROM_HERE, 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableFunction(&download_util::CancelDownloadRequest, 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resource_dispatcher_host_, 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->child_id, 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->request_id)); 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete info; 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile, 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick info, manager)); 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We don't forward an update to the UI thread here, since we want to throttle 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the UI update rate via a periodic timer. If the user has cancelled the 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// download (in the UI thread), we may receive a few more updates before the IO 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// thread gets the cancel message: we just delete the data since the 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DownloadFile has been deleted. 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<DownloadBuffer::Contents> contents; 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutoLock auto_lock(buffer->lock); 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents.swap(buffer->contents); 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadFile* download = GetDownloadFile(id); 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < contents.size(); ++i) { 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch net::IOBuffer* data = contents[i].first; 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int data_len = contents[i].second; 1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (download) 2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download->AppendDataToFile(data->data(), data_len); 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data->Release(); 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DownloadFileManager::OnResponseCompleted(int id, DownloadBuffer* buffer) { 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete buffer; 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadFileMap::iterator it = downloads_.find(id); 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it != downloads_.end()) { 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadFile* download = it->second; 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download->Finish(); 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadManager* download_manager = download->GetDownloadManager(); 2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (download_manager) { 2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::PostTask( 2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::UI, FROM_HERE, 2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NewRunnableMethod( 2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_manager, &DownloadManager::OnAllDataSaved, 2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick id, download->bytes_so_far())); 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to keep the download around until the UI thread has finalized 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the name. 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (download->path_renamed()) { 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch downloads_.erase(it); 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete download; 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (downloads_.empty()) 2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick StopUpdateTimer(); 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This method will be sent via a user action, or shutdown on the UI thread, and 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// run on the download thread. Since this message has been sent from the UI 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// thread, the download may have already completed and won't exist in our map. 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::CancelDownload(int id) { 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadFileMap::iterator it = downloads_.find(id); 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it != downloads_.end()) { 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadFile* download = it->second; 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download->Cancel(); 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (download->path_renamed()) { 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch downloads_.erase(it); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete download; 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (downloads_.empty()) 2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick StopUpdateTimer(); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) { 2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(manager); 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::set<DownloadFile*> to_remove; 2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (DownloadFileMap::iterator i = downloads_.begin(); 2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick i != downloads_.end(); ++i) { 2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadFile* download_file = i->second; 2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (download_file->GetDownloadManager() == manager) { 2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_file->CancelDownloadRequest(resource_dispatcher_host_); 2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick to_remove.insert(download_file); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (std::set<DownloadFile*>::iterator i = to_remove.begin(); 2703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick i != to_remove.end(); ++i) { 2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick downloads_.erase((*i)->id()); 2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick delete *i; 2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Actions from the UI thread and run on the download thread 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The DownloadManager in the UI thread has provided an intermediate .crdownload 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// name for the download specified by 'id'. Rename the in progress download. 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::OnIntermediateDownloadName( 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int id, const FilePath& full_path, DownloadManager* download_manager) 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch{ 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadFileMap::iterator it = downloads_.find(id); 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == downloads_.end()) 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadFile* download = it->second; 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!download->Rename(full_path, false)) { 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Error. Between the time the UI thread generated 'full_path' to the time 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this code runs, something happened that prevents us from renaming. 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CancelDownloadOnRename(id); 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The DownloadManager in the UI thread has provided a final name for the 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// download specified by 'id'. Rename the in progress download, and remove it 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// from our table if it has been completed or cancelled already. 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |need_delete_crdownload| indicates if we explicitly delete an intermediate 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// .crdownload file or not. 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// There are 3 possible rename cases where this method can be called: 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 1. tmp -> foo (need_delete_crdownload=T) 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 2. foo.crdownload -> foo (need_delete_crdownload=F) 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 3. tmp-> unconfirmed.xxx.crdownload (need_delete_crdownload=F) 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::OnFinalDownloadName(int id, 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& full_path, 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool need_delete_crdownload, 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadManager* manager) { 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadFile* download = GetDownloadFile(id); 3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!download) 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (download->Rename(full_path, true)) { 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX) 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Done here because we only want to do this once; see 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // http://crbug.com/13120 for details. 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download->AnnotateWithSourceInformation(); 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::PostTask( 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::UI, FROM_HERE, 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod( 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manager, &DownloadManager::DownloadRenamedToFinalName, id, 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch full_path)); 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Error. Between the time the UI thread generated 'full_path' to the time 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this code runs, something happened that prevents us from renaming. 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CancelDownloadOnRename(id); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (need_delete_crdownload) 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download->DeleteCrDownload(); 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the download has completed before we got this final name, we remove it 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // from our in progress map. 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!download->in_progress()) { 3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick downloads_.erase(id); 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete download; 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (downloads_.empty()) 3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick StopUpdateTimer(); 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called only from OnFinalDownloadName or OnIntermediateDownloadName 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// on the FILE thread. 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::CancelDownloadOnRename(int id) { 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadFile* download = GetDownloadFile(id); 3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!download) 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadManager* download_manager = download->GetDownloadManager(); 3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!download_manager) { 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download->CancelDownloadRequest(resource_dispatcher_host_); 3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::PostTask( 3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ChromeThread::UI, FROM_HERE, 3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NewRunnableMethod(download_manager, 3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick &DownloadManager::DownloadCancelled, id)); 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 367