download_file_manager.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
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"
12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/browser_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) {
40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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() {
65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::FILE, FROM_HERE,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &DownloadFileManager::OnShutdown));
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::OnShutdown() {
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  StopUpdateTimer();
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  STLDeleteValues(&downloads_);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DownloadFileManager::CreateDownloadFile(
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DownloadCreateInfo* info, DownloadManager* download_manager) {
79731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<DownloadFile> download_file(
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new DownloadFile(info, download_manager));
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!download_file->Initialize()) {
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::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.
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(this, &DownloadFileManager::ResumeDownloadRequest,
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        info->child_id, info->request_id));
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartUpdateTimer();
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::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) {
114731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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() {
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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() {
134731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  update_timer_.Stop();
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::UpdateInProgressDownloads() {
139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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) {
146731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(BrowserThread::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() {
156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return next_id_++;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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) {
167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::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
177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::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) {
188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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) {
206731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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) {
215731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
216731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::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) {
238731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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) {
255731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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{
283731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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) {
310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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
322731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
323731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::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) {
350731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::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
362731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
363731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(download_manager,
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        &DownloadManager::DownloadCancelled, id));
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
367