1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 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"
8201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "base/logging.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stl_util-inl.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.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"
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/safe_browsing/safe_browsing_service.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_util.h"
21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/resource_dispatcher_host.h"
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/io_buffer.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Throttle updates to the UI thread so that a fast moving download doesn't
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// cause it to become unresponsive (in milliseconds).
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kUpdatePeriodMs = 500;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickDownloadManager* DownloadManagerForRenderViewHost(int render_process_id,
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                  int render_view_id) {
35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TabContents* contents = tab_util::GetTabContentsByID(render_process_id,
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                       render_view_id);
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (contents) {
403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    Profile* profile = contents->profile();
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (profile)
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return profile->GetDownloadManager();
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return NULL;
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh)
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : next_id_(0),
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      resource_dispatcher_host_(rdh) {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadFileManager::~DownloadFileManager() {
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(downloads_.empty());
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::Shutdown() {
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
62731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::FILE, FROM_HERE,
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &DownloadFileManager::OnShutdown));
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::OnShutdown() {
67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  StopUpdateTimer();
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  STLDeleteValues(&downloads_);
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid DownloadFileManager::CreateDownloadFile(DownloadCreateInfo* info,
7372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                             DownloadManager* download_manager,
7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                             bool get_hash) {
75201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString();
76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  scoped_ptr<DownloadFile>
7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      download_file(new DownloadFile(info, download_manager));
8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!download_file->Initialize(get_hash)) {
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::IO, FROM_HERE,
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NewRunnableFunction(&download_util::CancelDownloadRequest,
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            resource_dispatcher_host_,
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            info->child_id,
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            info->request_id));
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete info;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(GetDownloadFile(info->download_id) == NULL);
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  downloads_[info->download_id] = download_file.release();
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(phajdan.jr): fix the duplication of path info below.
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  info->path = info->save_info.file_path;
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // The file is now ready, we can un-pause the request and start saving data.
97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(this, &DownloadFileManager::ResumeDownloadRequest,
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        info->child_id, info->request_id));
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartUpdateTimer();
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(download_manager,
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        &DownloadManager::StartDownload, info));
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DownloadFileManager::ResumeDownloadRequest(int child_id, int request_id) {
111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This balances the pause in DownloadResourceHandler::OnResponseStarted.
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  resource_dispatcher_host_->PauseRequest(child_id, request_id, false);
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadFile* DownloadFileManager::GetDownloadFile(int id) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DownloadFileMap::iterator it = downloads_.find(id);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return it == downloads_.end() ? NULL : it->second;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::StartUpdateTimer() {
123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!update_timer_.IsRunning()) {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        this, &DownloadFileManager::UpdateInProgressDownloads);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::StopUpdateTimer() {
131731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  update_timer_.Stop();
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::UpdateInProgressDownloads() {
136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (DownloadFileMap::iterator i = downloads_.begin();
1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       i != downloads_.end(); ++i) {
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    int id = i->first;
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DownloadFile* download_file = i->second;
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DownloadManager* manager = download_file->GetDownloadManager();
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (manager) {
143731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          NewRunnableMethod(manager, &DownloadManager::UpdateDownload,
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                            id, download_file->bytes_so_far()));
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called on the IO thread once the ResourceDispatcherHost has decided that a
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// request is a download.
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint DownloadFileManager::GetNextId() {
153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return next_id_++;
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(info);
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DownloadManager* manager = DownloadManagerForRenderViewHost(
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      info->child_id, info->render_view_id);
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!manager) {
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::IO, FROM_HERE,
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NewRunnableFunction(&download_util::CancelDownloadRequest,
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            resource_dispatcher_host_,
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            info->child_id,
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            info->request_id));
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete info;
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  manager->CreateDownloadItem(info);
17521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bool hash_needed = resource_dispatcher_host_->safe_browsing_service()->
17772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      DownloadBinHashNeeded();
17872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile,
18172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        info, make_scoped_refptr(manager), hash_needed));
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We don't forward an update to the UI thread here, since we want to throttle
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the UI update rate via a periodic timer. If the user has cancelled the
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// download (in the UI thread), we may receive a few more updates before the IO
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// thread gets the cancel message: we just delete the data since the
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DownloadFile has been deleted.
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) {
190731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<DownloadBuffer::Contents> contents;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(buffer->lock);
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    contents.swap(buffer->contents);
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DownloadFile* download = GetDownloadFile(id);
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < contents.size(); ++i) {
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net::IOBuffer* data = contents[i].first;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int data_len = contents[i].second;
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (download)
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      download->AppendDataToFile(data->data(), data_len);
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data->Release();
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadFileManager::OnResponseCompleted(
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int id,
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DownloadBuffer* buffer,
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int os_error,
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& security_info) {
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           << " os_error = " << os_error
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           << " security_info = \"" << security_info << "\"";
215731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete buffer;
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DownloadFile* download = GetDownloadFile(id);
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!download)
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  download->Finish();
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DownloadManager* download_manager = download->GetDownloadManager();
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!download_manager) {
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CancelDownload(id);
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string hash;
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!download->GetSha256Hash(&hash))
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    hash.clear();
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BrowserThread::PostTask(
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      BrowserThread::UI, FROM_HERE,
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NewRunnableMethod(
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        download_manager, &DownloadManager::OnResponseCompleted,
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        id, download->bytes_so_far(), os_error, hash));
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We need to keep the download around until the UI thread has finalized
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the name.
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This method will be sent via a user action, or shutdown on the UI thread, and
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// run on the download thread. Since this message has been sent from the UI
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// thread, the download may have already completed and won't exist in our map.
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::CancelDownload(int id) {
246201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  VLOG(20) << __FUNCTION__ << "()" << " id = " << id;
247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DownloadFileMap::iterator it = downloads_.find(id);
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (it == downloads_.end())
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DownloadFile* download = it->second;
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(20) << __FUNCTION__ << "()"
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           << " download = " << download->DebugString();
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  download->Cancel();
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EraseDownload(id);
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadFileManager::CompleteDownload(int id) {
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!ContainsKey(downloads_, id))
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DownloadFile* download_file = downloads_[id];
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(20) << " " << __FUNCTION__ << "()"
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           << " id = " << id
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           << " download_file = " << download_file->DebugString();
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  download_file->Detach();
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EraseDownload(id);
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) {
278731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(manager);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::set<DownloadFile*> to_remove;
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (DownloadFileMap::iterator i = downloads_.begin();
2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       i != downloads_.end(); ++i) {
2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DownloadFile* download_file = i->second;
2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (download_file->GetDownloadManager() == manager) {
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      download_file->CancelDownloadRequest(resource_dispatcher_host_);
2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      to_remove.insert(download_file);
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (std::set<DownloadFile*>::iterator i = to_remove.begin();
2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       i != to_remove.end(); ++i) {
2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    downloads_.erase((*i)->id());
2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    delete *i;
2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Actions from the UI thread and run on the download thread
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The DownloadManager in the UI thread has provided an intermediate .crdownload
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// name for the download specified by 'id'. Rename the in progress download.
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen//
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// There are 2 possible rename cases where this method can be called:
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// 1. tmp -> foo.crdownload (not final, safe)
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// 2. tmp-> Unconfirmed.xxx.crdownload (not final, dangerous)
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadFileManager::RenameInProgressDownloadFile(
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int id, const FilePath& full_path) {
309201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
310201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch           << " full_path = \"" << full_path.value() << "\"";
311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DownloadFile* download = GetDownloadFile(id);
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!download)
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
317201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  VLOG(20) << __FUNCTION__ << "()" << " download = " << download->DebugString();
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
319dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!download->Rename(full_path)) {
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Error. Between the time the UI thread generated 'full_path' to the time
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // this code runs, something happened that prevents us from renaming.
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CancelDownloadOnRename(id);
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The DownloadManager in the UI thread has provided a final name for the
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// download specified by 'id'. Rename the download that's in the process
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// of completing.
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
330dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// There are 2 possible rename cases where this method can be called:
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// 1. foo.crdownload -> foo (final, safe)
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// 2. Unconfirmed.xxx.crdownload -> xxx (final, validated)
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadFileManager::RenameCompletingDownloadFile(
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int id, const FilePath& full_path, bool overwrite_existing_file) {
335201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           << " overwrite_existing_file = " << overwrite_existing_file
337dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           << " full_path = \"" << full_path.value() << "\"";
338731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DownloadFile* download = GetDownloadFile(id);
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!download)
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(download->GetDownloadManager());
345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DownloadManager* download_manager = download->GetDownloadManager();
346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
347201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  VLOG(20) << __FUNCTION__ << "()" << " download = " << download->DebugString();
348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int uniquifier = 0;
350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FilePath new_path = full_path;
351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!overwrite_existing_file) {
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Make our name unique at this point, as if a dangerous file is
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // downloading and a 2nd download is started for a file with the same
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // name, they would have the same path.  This is because we uniquify
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // the name on download start, and at that time the first file does
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // not exists yet, so the second file gets the same name.
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // This should not happen in the SAFE case, and we check for that in the UI
358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // thread.
359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    uniquifier = download_util::GetUniquePathNumber(new_path);
360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (uniquifier > 0) {
361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      download_util::AppendNumberToPath(&new_path, uniquifier);
362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Rename the file, overwriting if necessary.
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!download->Rename(new_path)) {
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Error. Between the time the UI thread generated 'full_path' to the time
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // this code runs, something happened that prevents us from renaming.
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CancelDownloadOnRename(id);
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_MACOSX)
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Done here because we only want to do this once; see
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // http://crbug.com/13120 for details.
376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  download->AnnotateWithSourceInformation();
377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BrowserThread::PostTask(
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      BrowserThread::UI, FROM_HERE,
381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NewRunnableMethod(
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id,
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          new_path, uniquifier));
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Called only from RenameInProgressDownloadFile and
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// RenameCompletingDownloadFile on the FILE thread.
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadFileManager::CancelDownloadOnRename(int id) {
389731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
3903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DownloadFile* download = GetDownloadFile(id);
3923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!download)
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DownloadManager* download_manager = download->GetDownloadManager();
3963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!download_manager) {
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Without a download manager, we can't cancel the request normally, so we
398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // need to do it here.  The normal path will also update the download
399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // history before cancelling the request.
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    download->CancelDownloadRequest(resource_dispatcher_host_);
4013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
4033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
404731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
405731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
4063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(download_manager,
4073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        &DownloadManager::DownloadCancelled, id));
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
409dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
410dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid DownloadFileManager::EraseDownload(int id) {
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
413dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!ContainsKey(downloads_, id))
414dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
415dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
416dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DownloadFile* download_file = downloads_[id];
417dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(20) << " " << __FUNCTION__ << "()"
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           << " id = " << id
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           << " download_file = " << download_file->DebugString();
421dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  downloads_.erase(id);
423dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
424dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  delete download_file;
425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (downloads_.empty())
427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    StopUpdateTimer();
428dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
429