Move the core download files to content.
Review URL: http://codereview.chromium.org/7618048

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96829 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/browser/download/download_create_info.cc b/content/browser/download/download_create_info.cc
new file mode 100644
index 0000000..4b556ab
--- /dev/null
+++ b/content/browser/download/download_create_info.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_create_info.h"
+
+#include <string>
+
+#include "base/format_macros.h"
+#include "base/stringprintf.h"
+
+DownloadCreateInfo::DownloadCreateInfo(const FilePath& path,
+                                       const GURL& url,
+                                       const base::Time& start_time,
+                                       int64 received_bytes,
+                                       int64 total_bytes,
+                                       int32 state,
+                                       int32 download_id,
+                                       bool has_user_gesture)
+    : path(path),
+      url_chain(1, url),
+      path_uniquifier(0),
+      start_time(start_time),
+      received_bytes(received_bytes),
+      total_bytes(total_bytes),
+      state(state),
+      download_id(download_id),
+      has_user_gesture(has_user_gesture),
+      db_handle(0),
+      prompt_user_for_save_location(false),
+      is_extension_install(false) {
+}
+
+DownloadCreateInfo::DownloadCreateInfo()
+    : path_uniquifier(0),
+      received_bytes(0),
+      total_bytes(0),
+      state(-1),
+      download_id(-1),
+      has_user_gesture(false),
+      db_handle(0),
+      prompt_user_for_save_location(false),
+      is_extension_install(false) {
+}
+
+DownloadCreateInfo::~DownloadCreateInfo() {
+}
+
+std::string DownloadCreateInfo::DebugString() const {
+  return base::StringPrintf("{"
+                            " download_id = %d"
+                            " url = \"%s\""
+                            " path = \"%" PRFilePath "\""
+                            " received_bytes = %" PRId64
+                            " total_bytes = %" PRId64
+                            " request_handle = %s"
+                            " prompt_user_for_save_location = %c"
+                            " }",
+                            download_id,
+                            url().spec().c_str(),
+                            path.value().c_str(),
+                            received_bytes,
+                            total_bytes,
+                            request_handle.DebugString().c_str(),
+                            prompt_user_for_save_location ? 'T' : 'F');
+}
+
+const GURL& DownloadCreateInfo::url() const {
+  return url_chain.empty() ? GURL::EmptyGURL() : url_chain.back();
+}
diff --git a/content/browser/download/download_create_info.h b/content/browser/download/download_create_info.h
new file mode 100644
index 0000000..d2e5cd6
--- /dev/null
+++ b/content/browser/download/download_create_info.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_CREATE_INFO_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_CREATE_INFO_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/time.h"
+#include "content/browser/download/download_file.h"
+#include "content/browser/download/download_request_handle.h"
+#include "googleurl/src/gurl.h"
+
+// Used for informing the download manager of a new download, since we don't
+// want to pass |DownloadItem|s between threads.
+struct DownloadCreateInfo {
+  DownloadCreateInfo(const FilePath& path,
+                     const GURL& url,
+                     const base::Time& start_time,
+                     int64 received_bytes,
+                     int64 total_bytes,
+                     int32 state,
+                     int32 download_id,
+                     bool has_user_gesture);
+  DownloadCreateInfo();
+  ~DownloadCreateInfo();
+
+  std::string DebugString() const;
+
+  // The URL from which we are downloading. This is the final URL after any
+  // redirection by the server for |url_chain|.
+  const GURL& url() const;
+
+  // DownloadItem fields
+  // The path where we want to save the download file.
+  FilePath path;
+
+  // The chain of redirects that leading up to and including the final URL.
+  std::vector<GURL> url_chain;
+
+  // The URL that referred us.
+  GURL referrer_url;
+
+  // A number that should be added to the suggested path to make it unique.
+  // 0 means no number should be appended.  Not actually stored in the db.
+  int path_uniquifier;
+
+  // The time when the download started.
+  base::Time start_time;
+
+  // The number of bytes that have been received.
+  int64 received_bytes;
+
+  // The total download size.
+  int64 total_bytes;
+
+  // The current state of the download.
+  int32 state;
+
+  // The (per-session) ID of the download.
+  int32 download_id;
+
+  // True if the download was initiated by user action.
+  bool has_user_gesture;
+
+  // The handle to the download request information.  Used for operations
+  // outside the download system.
+  DownloadRequestHandle request_handle;
+
+  // The handle of the download in the history database.
+  int64 db_handle;
+
+  // The content-disposition string from the response header.
+  std::string content_disposition;
+
+  // The mime type string from the response header (may be overridden).
+  std::string mime_type;
+
+  // The value of the content type header sent with the downloaded item.  It
+  // may be different from |mime_type|, which may be set based on heuristics
+  // which may look at the file extension and first few bytes of the file.
+  std::string original_mime_type;
+
+  // True if we should display the 'save as...' UI and prompt the user
+  // for the download location.
+  // False if the UI should be supressed and the download performed to the
+  // default location.
+  bool prompt_user_for_save_location;
+
+  // The original name for a dangerous download.
+  FilePath original_name;
+
+  // Whether this download is for extension install or not.
+  bool is_extension_install;
+
+  // The charset of the referring page where the download request comes from.
+  // It's used to construct a suggested filename.
+  std::string referrer_charset;
+
+  // The download file save info.
+  DownloadSaveInfo save_info;
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_CREATE_INFO_H_
diff --git a/content/browser/download/download_file.cc b/content/browser/download/download_file.cc
new file mode 100644
index 0000000..95b6078
--- /dev/null
+++ b/content/browser/download/download_file.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_file.h"
+
+#include <string>
+
+#include "base/file_util.h"
+#include "base/stringprintf.h"
+#include "chrome/browser/download/download_util.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_manager.h"
+
+DownloadFile::DownloadFile(const DownloadCreateInfo* info,
+                           DownloadManager* download_manager)
+    : BaseFile(info->save_info.file_path,
+               info->url(),
+               info->referrer_url,
+               info->received_bytes,
+               info->save_info.file_stream),
+      id_(info->download_id),
+      request_handle_(info->request_handle),
+      download_manager_(download_manager) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+}
+
+DownloadFile::~DownloadFile() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+}
+
+void DownloadFile::CancelDownloadRequest() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  request_handle_.CancelRequest();
+}
+
+DownloadManager* DownloadFile::GetDownloadManager() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  return download_manager_.get();
+}
+
+std::string DownloadFile::DebugString() const {
+  return base::StringPrintf("{"
+                            " id_ = " "%d"
+                            " request_handle = %s"
+                            " Base File = %s"
+                            " }",
+                            id_,
+                            request_handle_.DebugString().c_str(),
+                            BaseFile::DebugString().c_str());
+}
diff --git a/content/browser/download/download_file.h b/content/browser/download/download_file.h
new file mode 100644
index 0000000..5edffc2
--- /dev/null
+++ b/content/browser/download/download_file.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_FILE_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_FILE_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "content/browser/download/base_file.h"
+#include "content/browser/download/download_request_handle.h"
+#include "content/browser/download/download_types.h"
+
+struct DownloadCreateInfo;
+class DownloadManager;
+class ResourceDispatcherHost;
+
+// These objects live exclusively on the download thread and handle the writing
+// operations for one download. These objects live only for the duration that
+// the download is 'in progress': once the download has been completed or
+// cancelled, the DownloadFile is destroyed.
+class DownloadFile : public BaseFile {
+ public:
+  DownloadFile(const DownloadCreateInfo* info,
+               DownloadManager* download_manager);
+  virtual ~DownloadFile();
+
+  // Cancels the download request associated with this file.
+  void CancelDownloadRequest();
+
+  int id() const { return id_; }
+  DownloadManager* GetDownloadManager();
+
+  virtual std::string DebugString() const;
+
+ private:
+  // The unique identifier for this download, assigned at creation by
+  // the DownloadFileManager for its internal record keeping.
+  int id_;
+
+  // The handle to the request information.  Used for operations outside the
+  // download system, specifically canceling a download.
+  DownloadRequestHandle request_handle_;
+
+  // DownloadManager this download belongs to.
+  scoped_refptr<DownloadManager> download_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadFile);
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_FILE_H_
diff --git a/content/browser/download/download_file_manager.cc b/content/browser/download/download_file_manager.cc
new file mode 100644
index 0000000..fb80d2f
--- /dev/null
+++ b/content/browser/download/download_file_manager.cc
@@ -0,0 +1,403 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_file_manager.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/task.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/common/pref_names.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_manager.h"
+#include "content/browser/renderer_host/resource_dispatcher_host.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/io_buffer.h"
+
+namespace {
+
+// Throttle updates to the UI thread so that a fast moving download doesn't
+// cause it to become unresponsive (in milliseconds).
+const int kUpdatePeriodMs = 500;
+
+}  // namespace
+
+DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh)
+    : next_id_(0),
+      resource_dispatcher_host_(rdh) {
+}
+
+DownloadFileManager::~DownloadFileManager() {
+  DCHECK(downloads_.empty());
+}
+
+void DownloadFileManager::Shutdown() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      NewRunnableMethod(this, &DownloadFileManager::OnShutdown));
+}
+
+void DownloadFileManager::OnShutdown() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  StopUpdateTimer();
+  STLDeleteValues(&downloads_);
+}
+
+void DownloadFileManager::CreateDownloadFile(DownloadCreateInfo* info,
+                                             DownloadManager* download_manager,
+                                             bool get_hash) {
+  DCHECK(info);
+  VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString();
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  // Life of |info| ends here. No more references to it after this method.
+  scoped_ptr<DownloadCreateInfo> infop(info);
+
+  scoped_ptr<DownloadFile>
+      download_file(new DownloadFile(info, download_manager));
+  if (!download_file->Initialize(get_hash)) {
+    info->request_handle.CancelRequest();
+    return;
+  }
+
+  int32 id = info->download_id;
+  DCHECK(GetDownloadFile(id) == NULL);
+  downloads_[id] = download_file.release();
+
+  // The file is now ready, we can un-pause the request and start saving data.
+  info->request_handle.ResumeRequest();
+
+  StartUpdateTimer();
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      NewRunnableMethod(download_manager,
+                        &DownloadManager::StartDownload, id));
+}
+
+DownloadFile* DownloadFileManager::GetDownloadFile(int id) {
+  DownloadFileMap::iterator it = downloads_.find(id);
+  return it == downloads_.end() ? NULL : it->second;
+}
+
+void DownloadFileManager::StartUpdateTimer() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  if (!update_timer_.IsRunning()) {
+    update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
+                        this, &DownloadFileManager::UpdateInProgressDownloads);
+  }
+}
+
+void DownloadFileManager::StopUpdateTimer() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  update_timer_.Stop();
+}
+
+void DownloadFileManager::UpdateInProgressDownloads() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  for (DownloadFileMap::iterator i = downloads_.begin();
+       i != downloads_.end(); ++i) {
+    int id = i->first;
+    DownloadFile* download_file = i->second;
+    DownloadManager* manager = download_file->GetDownloadManager();
+    if (manager) {
+      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+          NewRunnableMethod(manager, &DownloadManager::UpdateDownload,
+                            id, download_file->bytes_so_far()));
+    }
+  }
+}
+
+// Called on the IO thread once the ResourceDispatcherHost has decided that a
+// request is a download.
+int DownloadFileManager::GetNextId() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  return next_id_++;
+}
+
+void DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(info);
+
+  DownloadManager* manager = info->request_handle.GetDownloadManager();
+  if (!manager) {
+    info->request_handle.CancelRequest();
+    delete info;
+    return;
+  }
+
+  // TODO(phajdan.jr): fix the duplication of path info below.
+  info->path = info->save_info.file_path;
+
+  manager->CreateDownloadItem(info);
+
+#if defined(ENABLE_SAFE_BROWSING)
+  bool hash_needed = manager->profile()->GetPrefs()->GetBoolean(
+      prefs::kSafeBrowsingEnabled) &&
+          g_browser_process->safe_browsing_service()->DownloadBinHashNeeded();
+#else
+  bool hash_needed = false;
+#endif
+
+  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+      NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile,
+                        info, make_scoped_refptr(manager), hash_needed));
+}
+
+// We don't forward an update to the UI thread here, since we want to throttle
+// the UI update rate via a periodic timer. If the user has cancelled the
+// download (in the UI thread), we may receive a few more updates before the IO
+// thread gets the cancel message: we just delete the data since the
+// DownloadFile has been deleted.
+void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  std::vector<DownloadBuffer::Contents> contents;
+  {
+    base::AutoLock auto_lock(buffer->lock);
+    contents.swap(buffer->contents);
+  }
+
+  DownloadFile* download_file = GetDownloadFile(id);
+  for (size_t i = 0; i < contents.size(); ++i) {
+    net::IOBuffer* data = contents[i].first;
+    const int data_len = contents[i].second;
+    if (download_file)
+      download_file->AppendDataToFile(data->data(), data_len);
+    data->Release();
+  }
+}
+
+void DownloadFileManager::OnResponseCompleted(
+    int id,
+    DownloadBuffer* buffer,
+    int os_error,
+    const std::string& security_info) {
+  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
+           << " os_error = " << os_error
+           << " security_info = \"" << security_info << "\"";
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  delete buffer;
+  DownloadFile* download_file = GetDownloadFile(id);
+  if (!download_file)
+    return;
+
+  download_file->Finish();
+
+  DownloadManager* download_manager = download_file->GetDownloadManager();
+  if (!download_manager) {
+    CancelDownload(id);
+    return;
+  }
+
+  std::string hash;
+  if (!download_file->GetSha256Hash(&hash))
+    hash.clear();
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      NewRunnableMethod(
+        download_manager, &DownloadManager::OnResponseCompleted,
+        id, download_file->bytes_so_far(), os_error, hash));
+  // We need to keep the download around until the UI thread has finalized
+  // the name.
+}
+
+// This method will be sent via a user action, or shutdown on the UI thread, and
+// run on the download thread. Since this message has been sent from the UI
+// thread, the download may have already completed and won't exist in our map.
+void DownloadFileManager::CancelDownload(int id) {
+  VLOG(20) << __FUNCTION__ << "()" << " id = " << id;
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  DownloadFileMap::iterator it = downloads_.find(id);
+  if (it == downloads_.end())
+    return;
+
+  DownloadFile* download_file = it->second;
+  VLOG(20) << __FUNCTION__ << "()"
+           << " download_file = " << download_file->DebugString();
+  download_file->Cancel();
+
+  EraseDownload(id);
+}
+
+void DownloadFileManager::CompleteDownload(int id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  if (!ContainsKey(downloads_, id))
+    return;
+
+  DownloadFile* download_file = downloads_[id];
+
+  VLOG(20) << " " << __FUNCTION__ << "()"
+           << " id = " << id
+           << " download_file = " << download_file->DebugString();
+
+  download_file->Detach();
+
+  EraseDownload(id);
+}
+
+void DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  DCHECK(manager);
+
+  std::set<DownloadFile*> to_remove;
+
+  for (DownloadFileMap::iterator i = downloads_.begin();
+       i != downloads_.end(); ++i) {
+    DownloadFile* download_file = i->second;
+    if (download_file->GetDownloadManager() == manager) {
+      download_file->CancelDownloadRequest();
+      to_remove.insert(download_file);
+    }
+  }
+
+  for (std::set<DownloadFile*>::iterator i = to_remove.begin();
+       i != to_remove.end(); ++i) {
+    downloads_.erase((*i)->id());
+    delete *i;
+  }
+}
+
+// Actions from the UI thread and run on the download thread
+
+// The DownloadManager in the UI thread has provided an intermediate .crdownload
+// name for the download specified by 'id'. Rename the in progress download.
+//
+// There are 2 possible rename cases where this method can be called:
+// 1. tmp -> foo.crdownload (not final, safe)
+// 2. tmp-> Unconfirmed.xxx.crdownload (not final, dangerous)
+void DownloadFileManager::RenameInProgressDownloadFile(
+    int id, const FilePath& full_path) {
+  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
+           << " full_path = \"" << full_path.value() << "\"";
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  DownloadFile* download_file = GetDownloadFile(id);
+  if (!download_file)
+    return;
+
+  VLOG(20) << __FUNCTION__ << "()"
+           << " download_file = " << download_file->DebugString();
+
+  if (!download_file->Rename(full_path)) {
+    // Error. Between the time the UI thread generated 'full_path' to the time
+    // this code runs, something happened that prevents us from renaming.
+    CancelDownloadOnRename(id);
+  }
+}
+
+// The DownloadManager in the UI thread has provided a final name for the
+// download specified by 'id'. Rename the download that's in the process
+// of completing.
+//
+// There are 2 possible rename cases where this method can be called:
+// 1. foo.crdownload -> foo (final, safe)
+// 2. Unconfirmed.xxx.crdownload -> xxx (final, validated)
+void DownloadFileManager::RenameCompletingDownloadFile(
+    int id, const FilePath& full_path, bool overwrite_existing_file) {
+  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
+           << " overwrite_existing_file = " << overwrite_existing_file
+           << " full_path = \"" << full_path.value() << "\"";
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  DownloadFile* download_file = GetDownloadFile(id);
+  if (!download_file)
+    return;
+
+  DCHECK(download_file->GetDownloadManager());
+  DownloadManager* download_manager = download_file->GetDownloadManager();
+
+  VLOG(20) << __FUNCTION__ << "()"
+           << " download_file = " << download_file->DebugString();
+
+  int uniquifier = 0;
+  FilePath new_path = full_path;
+  if (!overwrite_existing_file) {
+    // Make our name unique at this point, as if a dangerous file is
+    // downloading and a 2nd download is started for a file with the same
+    // name, they would have the same path.  This is because we uniquify
+    // the name on download start, and at that time the first file does
+    // not exists yet, so the second file gets the same name.
+    // This should not happen in the SAFE case, and we check for that in the UI
+    // thread.
+    uniquifier = download_util::GetUniquePathNumber(new_path);
+    if (uniquifier > 0) {
+      download_util::AppendNumberToPath(&new_path, uniquifier);
+    }
+  }
+
+  // Rename the file, overwriting if necessary.
+  if (!download_file->Rename(new_path)) {
+    // Error. Between the time the UI thread generated 'full_path' to the time
+    // this code runs, something happened that prevents us from renaming.
+    CancelDownloadOnRename(id);
+    return;
+  }
+
+#if defined(OS_MACOSX)
+  // Done here because we only want to do this once; see
+  // http://crbug.com/13120 for details.
+  download_file->AnnotateWithSourceInformation();
+#endif
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      NewRunnableMethod(
+          download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id,
+          new_path, uniquifier));
+}
+
+// Called only from RenameInProgressDownloadFile and
+// RenameCompletingDownloadFile on the FILE thread.
+void DownloadFileManager::CancelDownloadOnRename(int id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  DownloadFile* download_file = GetDownloadFile(id);
+  if (!download_file)
+    return;
+
+  DownloadManager* download_manager = download_file->GetDownloadManager();
+  if (!download_manager) {
+    // Without a download manager, we can't cancel the request normally, so we
+    // need to do it here.  The normal path will also update the download
+    // history before cancelling the request.
+    download_file->CancelDownloadRequest();
+    return;
+  }
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      NewRunnableMethod(download_manager,
+                        &DownloadManager::DownloadCancelled, id));
+}
+
+void DownloadFileManager::EraseDownload(int id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  if (!ContainsKey(downloads_, id))
+    return;
+
+  DownloadFile* download_file = downloads_[id];
+
+  VLOG(20) << " " << __FUNCTION__ << "()"
+           << " id = " << id
+           << " download_file = " << download_file->DebugString();
+
+  downloads_.erase(id);
+
+  delete download_file;
+
+  if (downloads_.empty())
+    StopUpdateTimer();
+}
diff --git a/content/browser/download/download_file_manager.h b/content/browser/download/download_file_manager.h
new file mode 100644
index 0000000..45cef5e
--- /dev/null
+++ b/content/browser/download/download_file_manager.h
@@ -0,0 +1,173 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The DownloadFileManager owns a set of DownloadFile objects, each of which
+// represent one in progress download and performs the disk IO for that
+// download. The DownloadFileManager itself is a singleton object owned by the
+// ResourceDispatcherHost.
+//
+// The DownloadFileManager uses the file_thread for performing file write
+// operations, in order to avoid disk activity on either the IO (network) thread
+// and the UI thread. It coordinates the notifications from the network and UI.
+//
+// A typical download operation involves multiple threads:
+//
+// Updating an in progress download
+// io_thread
+//      |----> data ---->|
+//                     file_thread (writes to disk)
+//                              |----> stats ---->|
+//                                              ui_thread (feedback for user and
+//                                                         updates to history)
+//
+// Cancel operations perform the inverse order when triggered by a user action:
+// ui_thread (user click)
+//    |----> cancel command ---->|
+//                          file_thread (close file)
+//                                 |----> cancel command ---->|
+//                                                    io_thread (stops net IO
+//                                                               for download)
+//
+// The DownloadFileManager tracks download requests, mapping from a download
+// ID (unique integer created in the IO thread) to the DownloadManager for the
+// tab (profile) where the download was initiated. In the event of a tab closure
+// during a download, the DownloadFileManager will continue to route data to the
+// appropriate DownloadManager. In progress downloads are cancelled for a
+// DownloadManager that exits (such as when closing a profile).
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_FILE_MANAGER_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_FILE_MANAGER_H_
+#pragma once
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/timer.h"
+#include "content/browser/download/download_request_handle.h"
+#include "ui/gfx/native_widget_types.h"
+
+struct DownloadBuffer;
+struct DownloadCreateInfo;
+struct DownloadSaveInfo;
+class DownloadFile;
+class DownloadManager;
+class FilePath;
+class GURL;
+class ResourceDispatcherHost;
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+// Manages all in progress downloads.
+class DownloadFileManager
+    : public base::RefCountedThreadSafe<DownloadFileManager> {
+ public:
+  explicit DownloadFileManager(ResourceDispatcherHost* rdh);
+
+  // Called on shutdown on the UI thread.
+  void Shutdown();
+
+  // Called on the IO thread
+  int GetNextId();
+
+  // Called on UI thread to make DownloadFileManager start the download.
+  void StartDownload(DownloadCreateInfo* info);
+
+  // Handlers for notifications sent from the IO thread and run on the
+  // FILE thread.
+  void UpdateDownload(int id, DownloadBuffer* buffer);
+  // |os_error| is 0 for normal completions, and non-0 for errors.
+  // |security_info| contains SSL information (cert_id, cert_status,
+  // security_bits, ssl_connection_status), which can be used to
+  // fine-tune the error message.  It is empty if the transaction
+  // was not performed securely.
+  void OnResponseCompleted(int id,
+                           DownloadBuffer* buffer,
+                           int os_error,
+                           const std::string& security_info);
+
+  // Handlers for notifications sent from the UI thread and run on the
+  // FILE thread.  These are both terminal actions with respect to the
+  // download file, as far as the DownloadFileManager is concerned -- if
+  // anything happens to the download file after they are called, it will
+  // be ignored.
+  void CancelDownload(int id);
+  void CompleteDownload(int id);
+
+  // Called on FILE thread by DownloadManager at the beginning of its shutdown.
+  void OnDownloadManagerShutdown(DownloadManager* manager);
+
+  // The DownloadManager in the UI thread has provided an intermediate
+  // .crdownload name for the download specified by |id|.
+  void RenameInProgressDownloadFile(int id, const FilePath& full_path);
+
+  // The DownloadManager in the UI thread has provided a final name for the
+  // download specified by |id|.
+  // |overwrite_existing_file| prevents uniquification, and is used for SAFE
+  // downloads, as the user may have decided to overwrite the file.
+  // Sent from the UI thread and run on the FILE thread.
+  void RenameCompletingDownloadFile(int id,
+                                    const FilePath& full_path,
+                                    bool overwrite_existing_file);
+
+  // The number of downloads currently active on the DownloadFileManager.
+  // Primarily for testing.
+  int NumberOfActiveDownloads() const {
+    return downloads_.size();
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<DownloadFileManager>;
+  friend class DownloadManagerTest;
+  FRIEND_TEST_ALL_PREFIXES(DownloadManagerTest, StartDownload);
+
+  ~DownloadFileManager();
+
+  // Timer helpers for updating the UI about the current progress of a download.
+  void StartUpdateTimer();
+  void StopUpdateTimer();
+  void UpdateInProgressDownloads();
+
+  // Clean up helper that runs on the download thread.
+  void OnShutdown();
+
+  // Creates DownloadFile on FILE thread and continues starting the download
+  // process.
+  void CreateDownloadFile(DownloadCreateInfo* info,
+                          DownloadManager* download_manager,
+                          bool hash_needed);
+
+  // Called only on the download thread.
+  DownloadFile* GetDownloadFile(int id);
+
+  // Called only from RenameInProgressDownloadFile and
+  // RenameCompletingDownloadFile on the FILE thread.
+  void CancelDownloadOnRename(int id);
+
+  // Erases the download file with the given the download |id| and removes
+  // it from the maps.
+  void EraseDownload(int id);
+
+  // Unique ID for each DownloadFile.
+  int next_id_;
+
+  typedef base::hash_map<int, DownloadFile*> DownloadFileMap;
+
+  // A map of all in progress downloads.  It owns the download files.
+  DownloadFileMap downloads_;
+
+  // Schedule periodic updates of the download progress. This timer
+  // is controlled from the FILE thread, and posts updates to the UI thread.
+  base::RepeatingTimer<DownloadFileManager> update_timer_;
+
+  ResourceDispatcherHost* resource_dispatcher_host_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadFileManager);
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_FILE_MANAGER_H_
diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc
new file mode 100644
index 0000000..c257a237
--- /dev/null
+++ b/content/browser/download/download_file_unittest.cc
@@ -0,0 +1,196 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_number_conversions.h"
+#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/download/mock_download_manager_delegate.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_file.h"
+#include "content/browser/download/download_manager.h"
+#include "content/browser/download/download_request_handle.h"
+#include "content/browser/download/download_status_updater.h"
+#include "content/browser/download/mock_download_manager.h"
+#include "net/base/file_stream.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class DownloadFileTest : public testing::Test {
+ public:
+
+  static const char* kTestData1;
+  static const char* kTestData2;
+  static const char* kTestData3;
+  static const char* kDataHash;
+  static const int32 kDummyDownloadId;
+  static const int kDummyChildId;
+  static const int kDummyRequestId;
+
+  // We need a UI |BrowserThread| in order to destruct |download_manager_|,
+  // which has trait |BrowserThread::DeleteOnUIThread|.  Without this,
+  // calling Release() on |download_manager_| won't ever result in its
+  // destructor being called and we get a leak.
+  DownloadFileTest() :
+      ui_thread_(BrowserThread::UI, &loop_),
+      file_thread_(BrowserThread::FILE, &loop_) {
+  }
+
+  ~DownloadFileTest() {
+  }
+
+  virtual void SetUp() {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    download_manager_delegate_.reset(new MockDownloadManagerDelegate());
+    download_manager_ = new MockDownloadManager(
+        download_manager_delegate_.get(), &download_status_updater_);
+  }
+
+  virtual void TearDown() {
+    // When a DownloadManager's reference count drops to 0, it is not
+    // deleted immediately. Instead, a task is posted to the UI thread's
+    // message loop to delete it.
+    // So, drop the reference count to 0 and run the message loop once
+    // to ensure that all resources are cleaned up before the test exits.
+    download_manager_ = NULL;
+    ui_thread_.message_loop()->RunAllPending();
+  }
+
+  virtual void CreateDownloadFile(scoped_ptr<DownloadFile>* file, int offset) {
+    DownloadCreateInfo info;
+    info.download_id = kDummyDownloadId + offset;
+    // info.request_handle default constructed to null.
+    info.save_info.file_stream = file_stream_;
+    file->reset(new DownloadFile(&info, download_manager_));
+  }
+
+  virtual void DestroyDownloadFile(scoped_ptr<DownloadFile>* file, int offset) {
+    EXPECT_EQ(kDummyDownloadId + offset, (*file)->id());
+    EXPECT_EQ(download_manager_, (*file)->GetDownloadManager());
+    EXPECT_FALSE((*file)->in_progress());
+    EXPECT_EQ(static_cast<int64>(expected_data_.size()),
+              (*file)->bytes_so_far());
+
+    // Make sure the data has been properly written to disk.
+    std::string disk_data;
+    EXPECT_TRUE(file_util::ReadFileToString((*file)->full_path(),
+                                            &disk_data));
+    EXPECT_EQ(expected_data_, disk_data);
+
+    // Make sure the mock BrowserThread outlives the DownloadFile to satisfy
+    // thread checks inside it.
+    file->reset();
+  }
+
+  void AppendDataToFile(scoped_ptr<DownloadFile>* file,
+                        const std::string& data) {
+    EXPECT_TRUE((*file)->in_progress());
+    (*file)->AppendDataToFile(data.data(), data.size());
+    expected_data_ += data;
+    EXPECT_EQ(static_cast<int64>(expected_data_.size()),
+              (*file)->bytes_so_far());
+  }
+
+ protected:
+  // Temporary directory for renamed downloads.
+  ScopedTempDir temp_dir_;
+
+  DownloadStatusUpdater download_status_updater_;
+  scoped_ptr<MockDownloadManagerDelegate> download_manager_delegate_;
+  scoped_refptr<DownloadManager> download_manager_;
+
+  linked_ptr<net::FileStream> file_stream_;
+
+  // DownloadFile instance we are testing.
+  scoped_ptr<DownloadFile> download_file_;
+
+ private:
+  MessageLoop loop_;
+  // UI thread.
+  BrowserThread ui_thread_;
+  // File thread to satisfy debug checks in DownloadFile.
+  BrowserThread file_thread_;
+
+  // Keep track of what data should be saved to the disk file.
+  std::string expected_data_;
+};
+
+const char* DownloadFileTest::kTestData1 =
+    "Let's write some data to the file!\n";
+const char* DownloadFileTest::kTestData2 = "Writing more data.\n";
+const char* DownloadFileTest::kTestData3 = "Final line.";
+const char* DownloadFileTest::kDataHash =
+    "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8";
+
+const int32 DownloadFileTest::kDummyDownloadId = 23;
+const int DownloadFileTest::kDummyChildId = 3;
+const int DownloadFileTest::kDummyRequestId = 67;
+
+// Rename the file before any data is downloaded, after some has, after it all
+// has, and after it's closed.
+TEST_F(DownloadFileTest, RenameFileFinal) {
+  CreateDownloadFile(&download_file_, 0);
+  ASSERT_TRUE(download_file_->Initialize(true));
+  FilePath initial_path(download_file_->full_path());
+  EXPECT_TRUE(file_util::PathExists(initial_path));
+  FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
+  FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2"));
+  FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3"));
+  FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4"));
+
+  // Rename the file before downloading any data.
+  EXPECT_TRUE(download_file_->Rename(path_1));
+  FilePath renamed_path = download_file_->full_path();
+  EXPECT_EQ(path_1, renamed_path);
+
+  // Check the files.
+  EXPECT_FALSE(file_util::PathExists(initial_path));
+  EXPECT_TRUE(file_util::PathExists(path_1));
+
+  // Download the data.
+  AppendDataToFile(&download_file_, kTestData1);
+  AppendDataToFile(&download_file_, kTestData2);
+
+  // Rename the file after downloading some data.
+  EXPECT_TRUE(download_file_->Rename(path_2));
+  renamed_path = download_file_->full_path();
+  EXPECT_EQ(path_2, renamed_path);
+
+  // Check the files.
+  EXPECT_FALSE(file_util::PathExists(path_1));
+  EXPECT_TRUE(file_util::PathExists(path_2));
+
+  AppendDataToFile(&download_file_, kTestData3);
+
+  // Rename the file after downloading all the data.
+  EXPECT_TRUE(download_file_->Rename(path_3));
+  renamed_path = download_file_->full_path();
+  EXPECT_EQ(path_3, renamed_path);
+
+  // Check the files.
+  EXPECT_FALSE(file_util::PathExists(path_2));
+  EXPECT_TRUE(file_util::PathExists(path_3));
+
+  // Should not be able to get the hash until the file is closed.
+  std::string hash;
+  EXPECT_FALSE(download_file_->GetSha256Hash(&hash));
+
+  download_file_->Finish();
+
+  // Rename the file after downloading all the data and closing the file.
+  EXPECT_TRUE(download_file_->Rename(path_4));
+  renamed_path = download_file_->full_path();
+  EXPECT_EQ(path_4, renamed_path);
+
+  // Check the files.
+  EXPECT_FALSE(file_util::PathExists(path_3));
+  EXPECT_TRUE(file_util::PathExists(path_4));
+
+  // Check the hash.
+  EXPECT_TRUE(download_file_->GetSha256Hash(&hash));
+  EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
+
+  DestroyDownloadFile(&download_file_, 0);
+}
diff --git a/content/browser/download/download_item.cc b/content/browser/download/download_item.cc
new file mode 100644
index 0000000..2a9fd6e
--- /dev/null
+++ b/content/browser/download/download_item.cc
@@ -0,0 +1,865 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_item.h"
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/format_macros.h"
+#include "base/i18n/case_conversion.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/stringprintf.h"
+#include "base/timer.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/net_util.h"
+#include "chrome/browser/download/download_crx_util.h"
+#include "chrome/browser/download/download_extensions.h"
+#include "chrome/browser/download/download_history.h"
+#include "chrome/browser/download/download_manager_delegate.h"
+#include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/history/download_history_info.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/pref_names.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_file_manager.h"
+#include "content/browser/download/download_manager.h"
+#include "content/common/notification_source.h"
+
+// A DownloadItem normally goes through the following states:
+//      * Created (when download starts)
+//      * Made visible to consumers (e.g. Javascript) after the
+//        destination file has been determined.
+//      * Entered into the history database.
+//      * Made visible in the download shelf.
+//      * All data is saved.  Note that the actual data download occurs
+//        in parallel with the above steps, but until those steps are
+//        complete, completion of the data download will be ignored.
+//      * Download file is renamed to its final name, and possibly
+//        auto-opened.
+// TODO(rdsmith): This progress should be reflected in
+// DownloadItem::DownloadState and a state transition table/state diagram.
+//
+// TODO(rdsmith): This description should be updated to reflect the cancel
+// pathways.
+
+namespace {
+
+// Update frequency (milliseconds).
+const int kUpdateTimeMs = 1000;
+
+static void DeleteDownloadedFile(const FilePath& path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  // Make sure we only delete files.
+  if (!file_util::DirectoryExists(path))
+    file_util::Delete(path, false);
+}
+
+const char* DebugSafetyStateString(DownloadItem::SafetyState state) {
+  switch (state) {
+    case DownloadItem::SAFE:
+      return "SAFE";
+    case DownloadItem::DANGEROUS:
+      return "DANGEROUS";
+    case DownloadItem::DANGEROUS_BUT_VALIDATED:
+      return "DANGEROUS_BUT_VALIDATED";
+    default:
+      NOTREACHED() << "Unknown safety state " << state;
+      return "unknown";
+  };
+}
+
+const char* DebugDownloadStateString(DownloadItem::DownloadState state) {
+  switch (state) {
+    case DownloadItem::IN_PROGRESS:
+      return "IN_PROGRESS";
+    case DownloadItem::COMPLETE:
+      return "COMPLETE";
+    case DownloadItem::CANCELLED:
+      return "CANCELLED";
+    case DownloadItem::REMOVING:
+      return "REMOVING";
+    case DownloadItem::INTERRUPTED:
+      return "INTERRUPTED";
+    default:
+      NOTREACHED() << "Unknown download state " << state;
+      return "unknown";
+  };
+}
+
+DownloadItem::SafetyState GetSafetyState(bool dangerous_file,
+                                         bool dangerous_url) {
+  return (dangerous_url || dangerous_file) ?
+      DownloadItem::DANGEROUS : DownloadItem::SAFE;
+}
+
+// Note: When a download has both |dangerous_file| and |dangerous_url| set,
+// danger type is set to DANGEROUS_URL since the risk of dangerous URL
+// overweights that of dangerous file type.
+DownloadItem::DangerType GetDangerType(bool dangerous_file,
+                                       bool dangerous_url) {
+  if (dangerous_url) {
+    // dangerous URL overweights dangerous file. We check dangerous URL first.
+    return DownloadItem::DANGEROUS_URL;
+  }
+  return dangerous_file ?
+      DownloadItem::DANGEROUS_FILE : DownloadItem::NOT_DANGEROUS;
+}
+
+}  // namespace
+
+// Constructor for reading from the history service.
+DownloadItem::DownloadItem(DownloadManager* download_manager,
+                           const DownloadHistoryInfo& info)
+    : download_id_(-1),
+      full_path_(info.path),
+      url_chain_(1, info.url),
+      referrer_url_(info.referrer_url),
+      total_bytes_(info.total_bytes),
+      received_bytes_(info.received_bytes),
+      start_tick_(base::TimeTicks()),
+      state_(static_cast<DownloadState>(info.state)),
+      start_time_(info.start_time),
+      db_handle_(info.db_handle),
+      download_manager_(download_manager),
+      is_paused_(false),
+      open_when_complete_(false),
+      file_externally_removed_(false),
+      safety_state_(SAFE),
+      auto_opened_(false),
+      is_otr_(false),
+      is_temporary_(false),
+      all_data_saved_(false),
+      opened_(false),
+      open_enabled_(true) {
+  if (IsInProgress())
+    state_ = CANCELLED;
+  if (IsComplete())
+    all_data_saved_ = true;
+  Init(false /* not actively downloading */);
+}
+
+// Constructing for a regular download:
+DownloadItem::DownloadItem(DownloadManager* download_manager,
+                           const DownloadCreateInfo& info,
+                           bool is_otr)
+    : state_info_(info.original_name, info.save_info.file_path,
+                  info.has_user_gesture, info.prompt_user_for_save_location,
+                  info.path_uniquifier, false, false,
+                  info.is_extension_install),
+      request_handle_(info.request_handle),
+      download_id_(info.download_id),
+      full_path_(info.path),
+      url_chain_(info.url_chain),
+      referrer_url_(info.referrer_url),
+      suggested_filename_(UTF16ToUTF8(info.save_info.suggested_name)),
+      content_disposition_(info.content_disposition),
+      mime_type_(info.mime_type),
+      original_mime_type_(info.original_mime_type),
+      referrer_charset_(info.referrer_charset),
+      total_bytes_(info.total_bytes),
+      received_bytes_(0),
+      last_os_error_(0),
+      start_tick_(base::TimeTicks::Now()),
+      state_(IN_PROGRESS),
+      start_time_(info.start_time),
+      db_handle_(DownloadHistory::kUninitializedHandle),
+      download_manager_(download_manager),
+      is_paused_(false),
+      open_when_complete_(false),
+      file_externally_removed_(false),
+      safety_state_(SAFE),
+      auto_opened_(false),
+      is_otr_(is_otr),
+      is_temporary_(!info.save_info.file_path.empty()),
+      all_data_saved_(false),
+      opened_(false),
+      open_enabled_(true) {
+  Init(true /* actively downloading */);
+}
+
+// Constructing for the "Save Page As..." feature:
+DownloadItem::DownloadItem(DownloadManager* download_manager,
+                           const FilePath& path,
+                           const GURL& url,
+                           bool is_otr)
+    : download_id_(download_manager->GetNextSavePageId()),
+      full_path_(path),
+      url_chain_(1, url),
+      referrer_url_(GURL()),
+      total_bytes_(0),
+      received_bytes_(0),
+      last_os_error_(0),
+      start_tick_(base::TimeTicks::Now()),
+      state_(IN_PROGRESS),
+      start_time_(base::Time::Now()),
+      db_handle_(DownloadHistory::kUninitializedHandle),
+      download_manager_(download_manager),
+      is_paused_(false),
+      open_when_complete_(false),
+      file_externally_removed_(false),
+      safety_state_(SAFE),
+      auto_opened_(false),
+      is_otr_(is_otr),
+      is_temporary_(false),
+      all_data_saved_(false),
+      opened_(false),
+      open_enabled_(true) {
+  Init(true /* actively downloading */);
+}
+
+DownloadItem::~DownloadItem() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  TransitionTo(REMOVING);
+  download_manager_->AssertQueueStateConsistent(this);
+}
+
+void DownloadItem::AddObserver(Observer* observer) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  observers_.AddObserver(observer);
+}
+
+void DownloadItem::RemoveObserver(Observer* observer) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  observers_.RemoveObserver(observer);
+}
+
+void DownloadItem::UpdateObservers() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
+}
+
+bool DownloadItem::CanShowInFolder() {
+  return !IsCancelled() && !file_externally_removed_;
+}
+
+bool DownloadItem::CanOpenDownload() {
+  return !Extension::IsExtension(state_info_.target_name) &&
+    !file_externally_removed_;
+}
+
+bool DownloadItem::ShouldOpenFileBasedOnExtension() {
+  return download_manager_->delegate()->ShouldOpenFileBasedOnExtension(
+      GetUserVerifiedFilePath());
+}
+
+void DownloadItem::OpenFilesBasedOnExtension(bool open) {
+  DownloadPrefs* prefs = download_manager_->download_prefs();
+  if (open)
+    prefs->EnableAutoOpenBasedOnExtension(GetUserVerifiedFilePath());
+  else
+    prefs->DisableAutoOpenBasedOnExtension(GetUserVerifiedFilePath());
+}
+
+void DownloadItem::OpenDownload() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (IsPartialDownload()) {
+    open_when_complete_ = !open_when_complete_;
+  } else if (IsComplete() && !file_externally_removed_) {
+    // Ideally, we want to detect errors in opening and report them, but we
+    // don't generally have the proper interface for that to the external
+    // program that opens the file.  So instead we spawn a check to update
+    // the UI if the file has been deleted in parallel with the open.
+    download_manager_->CheckForFileRemoval(this);
+    opened_ = true;
+    FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
+
+    // For testing: If download opening is disabled on this item,
+    // make the rest of the routine a no-op.
+    if (!open_enabled_)
+      return;
+
+    if (is_extension_install()) {
+      download_crx_util::OpenChromeExtension(download_manager_->profile(),
+                                             *this);
+      return;
+    }
+#if defined(OS_MACOSX)
+    // Mac OS X requires opening downloads on the UI thread.
+    platform_util::OpenItem(full_path());
+#else
+    BrowserThread::PostTask(
+        BrowserThread::FILE, FROM_HERE,
+        NewRunnableFunction(&platform_util::OpenItem, full_path()));
+#endif
+  }
+}
+
+void DownloadItem::ShowDownloadInShell() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+#if defined(OS_MACOSX)
+  // Mac needs to run this operation on the UI thread.
+  platform_util::ShowItemInFolder(full_path());
+#else
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      NewRunnableFunction(&platform_util::ShowItemInFolder,
+                          full_path()));
+#endif
+}
+
+void DownloadItem::DangerousDownloadValidated() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK_EQ(DANGEROUS, safety_state());
+
+  UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated",
+                            GetDangerType(),
+                            DANGEROUS_TYPE_MAX);
+
+  safety_state_ = DANGEROUS_BUT_VALIDATED;
+  UpdateObservers();
+
+  download_manager_->MaybeCompleteDownload(this);
+}
+
+void DownloadItem::UpdateSize(int64 bytes_so_far) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  received_bytes_ = bytes_so_far;
+
+  // If we've received more data than we were expecting (bad server info?),
+  // revert to 'unknown size mode'.
+  if (received_bytes_ > total_bytes_)
+    total_bytes_ = 0;
+}
+
+void DownloadItem::StartProgressTimer() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdateTimeMs), this,
+                      &DownloadItem::UpdateObservers);
+}
+
+void DownloadItem::StopProgressTimer() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  update_timer_.Stop();
+}
+
+// Updates from the download thread may have been posted while this download
+// was being cancelled in the UI thread, so we'll accept them unless we're
+// complete.
+void DownloadItem::Update(int64 bytes_so_far) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (!IsInProgress()) {
+    NOTREACHED();
+    return;
+  }
+  UpdateSize(bytes_so_far);
+  UpdateObservers();
+}
+
+// Triggered by a user action.
+void DownloadItem::Cancel(bool update_history) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
+  if (!IsPartialDownload()) {
+    // Small downloads might be complete before this method has
+    // a chance to run.
+    return;
+  }
+
+  download_util::RecordDownloadCount(download_util::CANCELLED_COUNT);
+
+  TransitionTo(CANCELLED);
+  StopProgressTimer();
+  if (update_history)
+    download_manager_->DownloadCancelled(download_id_);
+}
+
+void DownloadItem::MarkAsComplete() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DCHECK(all_data_saved_);
+  TransitionTo(COMPLETE);
+}
+
+void DownloadItem::OnAllDataSaved(int64 size) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DCHECK(!all_data_saved_);
+  all_data_saved_ = true;
+  UpdateSize(size);
+  StopProgressTimer();
+}
+
+void DownloadItem::OnDownloadedFileRemoved() {
+  file_externally_removed_ = true;
+  UpdateObservers();
+}
+
+void DownloadItem::Completed() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
+
+  DCHECK(all_data_saved_);
+  TransitionTo(COMPLETE);
+  download_manager_->DownloadCompleted(id());
+  download_util::RecordDownloadCompleted(start_tick_);
+
+  if (is_extension_install()) {
+    // Extensions should already have been unpacked and opened.
+    DCHECK(auto_opened_);
+  } else if (open_when_complete() ||
+             ShouldOpenFileBasedOnExtension() ||
+             is_temporary()) {
+    // If the download is temporary, like in drag-and-drop, do not open it but
+    // we still need to set it auto-opened so that it can be removed from the
+    // download shelf.
+    if (!is_temporary())
+      OpenDownload();
+
+    auto_opened_ = true;
+    UpdateObservers();
+  }
+}
+
+void DownloadItem::StartCrxInstall() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DCHECK(is_extension_install());
+  DCHECK(all_data_saved_);
+
+  scoped_refptr<CrxInstaller> crx_installer =
+      download_crx_util::OpenChromeExtension(
+          download_manager_->profile(),
+          *this);
+
+  // CRX_INSTALLER_DONE will fire when the install completes.  Observe()
+  // will call Completed() on this item.  If this DownloadItem is not
+  // around when CRX_INSTALLER_DONE fires, Complete() will not be called.
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
+                 Source<CrxInstaller>(crx_installer.get()));
+
+  // The status text and percent complete indicator will change now
+  // that we are installing a CRX.  Update observers so that they pick
+  // up the change.
+  UpdateObservers();
+}
+
+void DownloadItem::TransitionTo(DownloadState new_state) {
+  if (state_ == new_state)
+    return;
+
+  state_ = new_state;
+  UpdateObservers();
+}
+
+void DownloadItem::UpdateSafetyState() {
+  SafetyState updated_value(
+      GetSafetyState(state_info_.is_dangerous_file,
+                     state_info_.is_dangerous_url));
+  if (updated_value != safety_state_) {
+    safety_state_ = updated_value;
+    UpdateObservers();
+  }
+}
+
+void DownloadItem::UpdateTarget() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (state_info_.target_name.value().empty())
+    state_info_.target_name = full_path_.BaseName();
+}
+
+// NotificationObserver implementation.
+void DownloadItem::Observe(int type,
+                           const NotificationSource& source,
+                           const NotificationDetails& details) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DCHECK(type == chrome::NOTIFICATION_CRX_INSTALLER_DONE);
+
+  // No need to listen for CRX_INSTALLER_DONE anymore.
+  registrar_.Remove(this,
+                    chrome::NOTIFICATION_CRX_INSTALLER_DONE,
+                    source);
+
+  auto_opened_ = true;
+  DCHECK(all_data_saved_);
+
+  Completed();
+}
+
+void DownloadItem::Interrupted(int64 size, int os_error) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (!IsInProgress())
+    return;
+
+  last_os_error_ = os_error;
+  UpdateSize(size);
+  StopProgressTimer();
+  download_util::RecordDownloadInterrupted(os_error,
+                                           received_bytes_,
+                                           total_bytes_);
+  TransitionTo(INTERRUPTED);
+}
+
+void DownloadItem::Delete(DeleteReason reason) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  switch (reason) {
+    case DELETE_DUE_TO_USER_DISCARD:
+      UMA_HISTOGRAM_ENUMERATION("Download.UserDiscard", GetDangerType(),
+                                DANGEROUS_TYPE_MAX);
+      break;
+    case DELETE_DUE_TO_BROWSER_SHUTDOWN:
+      UMA_HISTOGRAM_ENUMERATION("Download.Discard", GetDangerType(),
+                                DANGEROUS_TYPE_MAX);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+      NewRunnableFunction(&DeleteDownloadedFile, full_path_));
+  Remove();
+  // We have now been deleted.
+}
+
+void DownloadItem::Remove() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  download_manager_->AssertQueueStateConsistent(this);
+  Cancel(true);
+  download_manager_->AssertQueueStateConsistent(this);
+
+  TransitionTo(REMOVING);
+  download_manager_->RemoveDownload(db_handle_);
+  // We have now been deleted.
+}
+
+bool DownloadItem::TimeRemaining(base::TimeDelta* remaining) const {
+  if (total_bytes_ <= 0)
+    return false;  // We never received the content_length for this download.
+
+  int64 speed = CurrentSpeed();
+  if (speed == 0)
+    return false;
+
+  *remaining = base::TimeDelta::FromSeconds(
+      (total_bytes_ - received_bytes_) / speed);
+  return true;
+}
+
+int64 DownloadItem::CurrentSpeed() const {
+  if (is_paused_)
+    return 0;
+  base::TimeDelta diff = base::TimeTicks::Now() - start_tick_;
+  int64 diff_ms = diff.InMilliseconds();
+  return diff_ms == 0 ? 0 : received_bytes_ * 1000 / diff_ms;
+}
+
+int DownloadItem::PercentComplete() const {
+  // We don't have an accurate way to estimate the time to unpack a CRX.
+  // The slowest part is re-encoding images, and time to do this depends on
+  // the contents of the image.  If a CRX is being unpacked, indicate that
+  // we do not know how close to completion we are.
+  if (IsCrxInstallRuning() || total_bytes_ <= 0)
+    return -1;
+
+  return static_cast<int>(received_bytes_ * 100.0 / total_bytes_);
+}
+
+void DownloadItem::OnPathDetermined(const FilePath& path) {
+  full_path_ = path;
+  UpdateTarget();
+}
+
+void DownloadItem::Rename(const FilePath& full_path) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  VLOG(20) << __FUNCTION__ << "()"
+           << " full_path = \"" << full_path.value() << "\""
+           << " " << DebugString(true);
+  DCHECK(!full_path.empty());
+  full_path_ = full_path;
+}
+
+void DownloadItem::TogglePause() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DCHECK(IsInProgress());
+  if (is_paused_)
+    request_handle_.ResumeRequest();
+  else
+    request_handle_.PauseRequest();
+  is_paused_ = !is_paused_;
+  UpdateObservers();
+}
+
+void DownloadItem::OnDownloadCompleting(DownloadFileManager* file_manager) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  VLOG(20) << __FUNCTION__ << "()"
+           << " needs rename = " << NeedsRename()
+           << " " << DebugString(true);
+  DCHECK_NE(DANGEROUS, safety_state());
+  DCHECK(file_manager);
+
+  if (NeedsRename()) {
+    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+        NewRunnableMethod(file_manager,
+            &DownloadFileManager::RenameCompletingDownloadFile, id(),
+            GetTargetFilePath(), safety_state() == SAFE));
+    return;
+  }
+
+  DCHECK(!is_extension_install());
+  Completed();
+
+  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+      NewRunnableMethod(file_manager, &DownloadFileManager::CompleteDownload,
+                        id()));
+}
+
+void DownloadItem::OnDownloadRenamedToFinalName(const FilePath& full_path) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  VLOG(20) << __FUNCTION__ << "()"
+           << " full_path = \"" << full_path.value() << "\""
+           << " needed rename = " << NeedsRename()
+           << " " << DebugString(false);
+  DCHECK(NeedsRename());
+
+  Rename(full_path);
+
+  if (is_extension_install()) {
+    StartCrxInstall();
+    // Completed() will be called when the installer finishes.
+    return;
+  }
+
+  Completed();
+}
+
+bool DownloadItem::MatchesQuery(const string16& query) const {
+  if (query.empty())
+    return true;
+
+  DCHECK_EQ(query, base::i18n::ToLower(query));
+
+  string16 url_raw(base::i18n::ToLower(UTF8ToUTF16(GetURL().spec())));
+  if (url_raw.find(query) != string16::npos)
+    return true;
+
+  // TODO(phajdan.jr): write a test case for the following code.
+  // A good test case would be:
+  //   "/\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xbd\xa0\xe5\xa5\xbd",
+  //   L"/\x4f60\x597d\x4f60\x597d",
+  //   "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD"
+  PrefService* prefs = download_manager_->profile()->GetPrefs();
+  std::string languages(prefs->GetString(prefs::kAcceptLanguages));
+  string16 url_formatted(
+      base::i18n::ToLower(net::FormatUrl(GetURL(), languages)));
+  if (url_formatted.find(query) != string16::npos)
+    return true;
+
+  string16 path(base::i18n::ToLower(full_path().LossyDisplayName()));
+  // This shouldn't just do a substring match; it is wrong for Unicode
+  // due to normalization and we have a fancier search-query system
+  // used elsewhere.
+  // http://code.google.com/p/chromium/issues/detail?id=71982
+  return (path.find(query) != string16::npos);
+}
+
+void DownloadItem::SetFileCheckResults(const DownloadStateInfo& state) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true);
+  state_info_ = state;
+  VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true);
+
+  UpdateSafetyState();
+}
+
+DownloadItem::DangerType DownloadItem::GetDangerType() const {
+  return ::GetDangerType(state_info_.is_dangerous_file,
+                         state_info_.is_dangerous_url);
+}
+
+bool DownloadItem::IsDangerous() const {
+  return GetDangerType() != DownloadItem::NOT_DANGEROUS;
+}
+
+void DownloadItem::MarkFileDangerous() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  state_info_.is_dangerous_file = true;
+  UpdateSafetyState();
+}
+
+void DownloadItem::MarkUrlDangerous() {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  state_info_.is_dangerous_url = true;
+  UpdateSafetyState();
+}
+
+DownloadHistoryInfo DownloadItem::GetHistoryInfo() const {
+  return DownloadHistoryInfo(full_path(),
+                             GetURL(),
+                             referrer_url(),
+                             start_time(),
+                             received_bytes(),
+                             total_bytes(),
+                             state(),
+                             db_handle());
+}
+
+FilePath DownloadItem::GetTargetFilePath() const {
+  return full_path_.DirName().Append(state_info_.target_name);
+}
+
+FilePath DownloadItem::GetFileNameToReportUser() const {
+  if (state_info_.path_uniquifier > 0) {
+    FilePath name(state_info_.target_name);
+    download_util::AppendNumberToPath(&name, state_info_.path_uniquifier);
+    return name;
+  }
+  return state_info_.target_name;
+}
+
+FilePath DownloadItem::GetUserVerifiedFilePath() const {
+  return (safety_state_ == DownloadItem::SAFE) ?
+      GetTargetFilePath() : full_path_;
+}
+
+void DownloadItem::Init(bool active) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  UpdateTarget();
+  if (active) {
+    StartProgressTimer();
+    download_util::RecordDownloadCount(download_util::START_COUNT);
+  }
+  VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
+}
+
+// TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to
+// |IsPartialDownload()|, when resuming interrupted downloads is implemented.
+bool DownloadItem::IsPartialDownload() const {
+  return (state_ == IN_PROGRESS);
+}
+
+bool DownloadItem::IsInProgress() const {
+  return (state_ == IN_PROGRESS);
+}
+
+bool DownloadItem::IsCancelled() const {
+  return (state_ == CANCELLED) ||
+         (state_ == INTERRUPTED);
+}
+
+bool DownloadItem::IsInterrupted() const {
+  return (state_ == INTERRUPTED);
+}
+
+bool DownloadItem::IsComplete() const {
+  return (state_ == COMPLETE);
+}
+
+const GURL& DownloadItem::GetURL() const {
+  return url_chain_.empty() ?
+             GURL::EmptyGURL() : url_chain_.back();
+}
+
+std::string DownloadItem::DebugString(bool verbose) const {
+  std::string description =
+      base::StringPrintf("{ id = %d"
+                         " state = %s",
+                         download_id_,
+                         DebugDownloadStateString(state()));
+
+  // Construct a string of the URL chain.
+  std::string url_list("<none>");
+  if (!url_chain_.empty()) {
+    std::vector<GURL>::const_iterator iter = url_chain_.begin();
+    std::vector<GURL>::const_iterator last = url_chain_.end();
+    url_list = (*iter).spec();
+    ++iter;
+    for ( ; verbose && (iter != last); ++iter) {
+      url_list += " ->\n\t";
+      const GURL& next_url = *iter;
+      url_list += next_url.spec();
+    }
+  }
+
+  if (verbose) {
+    description += base::StringPrintf(
+        " db_handle = %" PRId64
+        " total_bytes = %" PRId64
+        " received_bytes = %" PRId64
+        " is_paused = %c"
+        " is_extension_install = %c"
+        " is_otr = %c"
+        " safety_state = %s"
+        " url_chain = \n\t\"%s\"\n\t"
+        " target_name = \"%" PRFilePath "\""
+        " full_path = \"%" PRFilePath "\"",
+        db_handle(),
+        total_bytes(),
+        received_bytes(),
+        is_paused() ? 'T' : 'F',
+        is_extension_install() ? 'T' : 'F',
+        is_otr() ? 'T' : 'F',
+        DebugSafetyStateString(safety_state()),
+        url_list.c_str(),
+        state_info_.target_name.value().c_str(),
+        full_path().value().c_str());
+  } else {
+    description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
+  }
+
+  description += " }";
+
+  return description;
+}
diff --git a/content/browser/download/download_item.h b/content/browser/download/download_item.h
new file mode 100644
index 0000000..3a90253
--- /dev/null
+++ b/content/browser/download/download_item.h
@@ -0,0 +1,493 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Each download is represented by a DownloadItem, and all DownloadItems
+// are owned by the DownloadManager which maintains a global list of all
+// downloads. DownloadItems are created when a user initiates a download,
+// and exist for the duration of the browser life time.
+//
+// Download observers:
+//   DownloadItem::Observer:
+//     - allows observers to receive notifications about one download from start
+//       to completion
+// Use AddObserver() / RemoveObserver() on the appropriate download object to
+// receive state updates.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/observer_list.h"
+#include "base/time.h"
+#include "base/timer.h"
+#include "content/browser/download/download_request_handle.h"
+#include "content/browser/download/download_state_info.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
+#include "googleurl/src/gurl.h"
+
+class CrxInstaller;
+class DownloadFileManager;
+class DownloadManager;
+struct DownloadCreateInfo;
+struct DownloadHistoryInfo;
+
+// One DownloadItem per download. This is the model class that stores all the
+// state for a download. Multiple views, such as a tab's download shelf and the
+// Destination tab's download view, may refer to a given DownloadItem.
+//
+// This is intended to be used only on the UI thread.
+class DownloadItem : public NotificationObserver {
+ public:
+  enum DownloadState {
+    // Download is actively progressing.
+    IN_PROGRESS = 0,
+
+    // Download is completely finished.
+    COMPLETE,
+
+    // Download has been cancelled.
+    CANCELLED,
+
+    // This state indicates that the download item is about to be destroyed,
+    // and observers seeing this state should release all references.
+    REMOVING,
+
+    // This state indicates that the download has been interrupted.
+    INTERRUPTED,
+
+    // Maximum value.
+    MAX_DOWNLOAD_STATE
+  };
+
+  enum SafetyState {
+    SAFE = 0,
+    DANGEROUS,
+    DANGEROUS_BUT_VALIDATED  // Dangerous but the user confirmed the download.
+  };
+
+  // This enum is used by histograms.  Do not change the ordering or remove
+  // items.
+  enum DangerType {
+    NOT_DANGEROUS = 0,
+
+    // A dangerous file to the system (e.g.: an executable or extension from
+    // places other than gallery).
+    DANGEROUS_FILE,
+
+    // Safebrowsing service shows this URL leads to malicious file download.
+    DANGEROUS_URL,
+
+    // Memory space for histograms is determined by the max.
+    // ALWAYS ADD NEW VALUES BEFORE THIS ONE.
+    DANGEROUS_TYPE_MAX
+  };
+
+  // Reason for deleting the download.  Passed to Delete().
+  enum DeleteReason {
+    DELETE_DUE_TO_BROWSER_SHUTDOWN = 0,
+    DELETE_DUE_TO_USER_DISCARD
+  };
+
+  // Interface that observers of a particular download must implement in order
+  // to receive updates to the download's status.
+  class Observer {
+   public:
+    virtual void OnDownloadUpdated(DownloadItem* download) = 0;
+
+    // Called when a downloaded file has been opened.
+    virtual void OnDownloadOpened(DownloadItem* download) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  // Constructing from persistent store:
+  DownloadItem(DownloadManager* download_manager,
+               const DownloadHistoryInfo& info);
+
+  // Constructing for a regular download:
+  DownloadItem(DownloadManager* download_manager,
+               const DownloadCreateInfo& info,
+               bool is_otr);
+
+  // Constructing for the "Save Page As..." feature:
+  DownloadItem(DownloadManager* download_manager,
+               const FilePath& path,
+               const GURL& url,
+               bool is_otr);
+
+  virtual ~DownloadItem();
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+  // Notifies our observers periodically.
+  void UpdateObservers();
+
+  // NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details);
+
+  // Returns true if it is OK to open a folder which this file is inside.
+  bool CanShowInFolder();
+
+  // Returns true if it is OK to register the type of this file so that
+  // it opens automatically.
+  bool CanOpenDownload();
+
+  // Tests if a file type should be opened automatically.
+  bool ShouldOpenFileBasedOnExtension();
+
+  // Registers this file extension for automatic opening upon download
+  // completion if 'open' is true, or prevents the extension from automatic
+  // opening if 'open' is false.
+  void OpenFilesBasedOnExtension(bool open);
+
+  // Open the file associated with this download (wait for the download to
+  // complete if it is in progress).
+  void OpenDownload();
+
+  // Show the download via the OS shell.
+  void ShowDownloadInShell();
+
+  // Called when the user has validated the download of a dangerous file.
+  void DangerousDownloadValidated();
+
+  // Received a new chunk of data
+  void Update(int64 bytes_so_far);
+
+  // Cancel the download operation. We need to distinguish between cancels at
+  // exit (DownloadManager destructor) from user interface initiated cancels
+  // because at exit, the history system may not exist, and any updates to it
+  // require AddRef'ing the DownloadManager in the destructor which results in
+  // a DCHECK failure. Set 'update_history' to false when canceling from at
+  // exit to prevent this crash. This may result in a difference between the
+  // downloaded file's size on disk, and what the history system's last record
+  // of it is. At worst, we'll end up re-downloading a small portion of the file
+  // when resuming a download (assuming the server supports byte ranges).
+  void Cancel(bool update_history);
+
+  // Called by external code (SavePackage) using the DownloadItem interface
+  // to display progress when the DownloadItem should be considered complete.
+  void MarkAsComplete();
+
+  // Called when all data has been saved. Only has display effects.
+  void OnAllDataSaved(int64 size);
+
+  // Called when the downloaded file is removed.
+  void OnDownloadedFileRemoved();
+
+  // Download operation had an error.
+  // |size| is the amount of data received so far, and |os_error| is the error
+  // code that the operation received.
+  void Interrupted(int64 size, int os_error);
+
+  // Deletes the file from disk and removes the download from the views and
+  // history.  |user| should be true if this is the result of the user clicking
+  // the discard button, and false if it is being deleted for other reasons like
+  // browser shutdown.
+  void Delete(DeleteReason reason);
+
+  // Removes the download from the views and history.
+  void Remove();
+
+  // Simple calculation of the amount of time remaining to completion. Fills
+  // |*remaining| with the amount of time remaining if successful. Fails and
+  // returns false if we do not have the number of bytes or the speed so can
+  // not estimate.
+  bool TimeRemaining(base::TimeDelta* remaining) const;
+
+  // Simple speed estimate in bytes/s
+  int64 CurrentSpeed() const;
+
+  // Rough percent complete, -1 means we don't know (since we didn't receive a
+  // total size).
+  int PercentComplete() const;
+
+  // Called when the final path has been determined.
+  void OnPathDetermined(const FilePath& path);
+
+  // Returns true if this download has saved all of its data.
+  bool all_data_saved() const { return all_data_saved_; }
+
+  // Update the fields that may have changed in DownloadStateInfo as a
+  // result of analyzing the file and figuring out its type, location, etc.
+  // May only be called once.
+  void SetFileCheckResults(const DownloadStateInfo& state);
+
+  // Update the download's path, the actual file is renamed on the download
+  // thread.
+  void Rename(const FilePath& full_path);
+
+  // Allow the user to temporarily pause a download or resume a paused download.
+  void TogglePause();
+
+  // Called when the download is ready to complete.
+  // This may perform final rename if necessary and will eventually call
+  // DownloadItem::Completed().
+  void OnDownloadCompleting(DownloadFileManager* file_manager);
+
+  // Called when the file name for the download is renamed to its final name.
+  void OnDownloadRenamedToFinalName(const FilePath& full_path);
+
+  // Returns true if this item matches |query|. |query| must be lower-cased.
+  bool MatchesQuery(const string16& query) const;
+
+  // Returns true if the download needs more data.
+  bool IsPartialDownload() const;
+
+  // Returns true if the download is still receiving data.
+  bool IsInProgress() const;
+
+  // Returns true if the download has been cancelled or was interrupted.
+  bool IsCancelled() const;
+
+  // Returns true if the download was interrupted.
+  bool IsInterrupted() const;
+
+  // Returns true if we have all the data and know the final file name.
+  bool IsComplete() const;
+
+  // Accessors
+  DownloadState state() const { return state_; }
+  const FilePath& full_path() const { return full_path_; }
+  void set_path_uniquifier(int uniquifier) {
+    state_info_.path_uniquifier = uniquifier;
+  }
+  const GURL& GetURL() const;
+
+  const std::vector<GURL>& url_chain() const { return url_chain_; }
+  const GURL& original_url() const { return url_chain_.front(); }
+  const GURL& referrer_url() const { return referrer_url_; }
+  std::string suggested_filename() const { return suggested_filename_; }
+  std::string content_disposition() const { return content_disposition_; }
+  std::string mime_type() const { return mime_type_; }
+  std::string original_mime_type() const { return original_mime_type_; }
+  std::string referrer_charset() const { return referrer_charset_; }
+  int64 total_bytes() const { return total_bytes_; }
+  void set_total_bytes(int64 total_bytes) {
+    total_bytes_ = total_bytes;
+  }
+  int64 received_bytes() const { return received_bytes_; }
+  int32 id() const { return download_id_; }
+  base::Time start_time() const { return start_time_; }
+  void set_db_handle(int64 handle) { db_handle_ = handle; }
+  int64 db_handle() const { return db_handle_; }
+  bool is_paused() const { return is_paused_; }
+  bool open_when_complete() const { return open_when_complete_; }
+  void set_open_when_complete(bool open) { open_when_complete_ = open; }
+  bool file_externally_removed() const { return file_externally_removed_; }
+  SafetyState safety_state() const { return safety_state_; }
+  // Why |safety_state_| is not SAFE.
+  DangerType GetDangerType() const;
+  bool IsDangerous() const;
+  void MarkFileDangerous();
+  void MarkUrlDangerous();
+
+  bool auto_opened() { return auto_opened_; }
+  const FilePath& target_name() const { return state_info_.target_name; }
+  bool prompt_user_for_save_location() const {
+    return state_info_.prompt_user_for_save_location;
+  }
+  bool is_otr() const { return is_otr_; }
+  bool is_extension_install() const {
+    return state_info_.is_extension_install;
+  }
+  const FilePath& suggested_path() const { return state_info_.suggested_path; }
+  bool is_temporary() const { return is_temporary_; }
+  void set_opened(bool opened) { opened_ = opened; }
+  bool opened() const { return opened_; }
+
+  DownloadHistoryInfo GetHistoryInfo() const;
+  DownloadStateInfo state_info() const { return state_info_; }
+  const DownloadRequestHandle& request_handle() const {
+    return request_handle_;
+  }
+
+  // Returns the final target file path for the download.
+  FilePath GetTargetFilePath() const;
+
+  // Returns the file-name that should be reported to the user, which is
+  // target_name possibly with the uniquifier number.
+  FilePath GetFileNameToReportUser() const;
+
+  // Returns the user-verified target file path for the download.
+  // This returns the same path as GetTargetFilePath() for safe downloads
+  // but does not for dangerous downloads until the name is verified.
+  FilePath GetUserVerifiedFilePath() const;
+
+  // Returns true if the current file name is not the final target name yet.
+  bool NeedsRename() const {
+    return state_info_.target_name != full_path_.BaseName();
+  }
+
+  // Is a CRX installer running on this download?
+  bool IsCrxInstallRuning() const {
+    return (is_extension_install() &&
+            all_data_saved() &&
+            state_ == IN_PROGRESS);
+  }
+
+  std::string DebugString(bool verbose) const;
+
+#ifdef UNIT_TEST
+  // Mock opening downloads (for testing only).
+  void TestMockDownloadOpen() { open_enabled_ = false; }
+#endif
+
+ private:
+  // Construction common to all constructors. |active| should be true for new
+  // downloads and false for downloads from the history.
+  void Init(bool active);
+
+  // Internal helper for maintaining consistent received and total sizes.
+  void UpdateSize(int64 size);
+
+  // Called when the entire download operation (including renaming etc)
+  // is completed.
+  void Completed();
+
+  // Start/stop sending periodic updates to our observers
+  void StartProgressTimer();
+  void StopProgressTimer();
+
+  // Call to install this item as a CRX. Should only be called on
+  // items which are CRXes. Use is_extension_install() to check.
+  void StartCrxInstall();
+
+  // Call to transition state; all state transitions should go through this.
+  void TransitionTo(DownloadState new_state);
+
+  // Called when safety_state_ should be recomputed from is_dangerous_file
+  // and is_dangerous_url.
+  void UpdateSafetyState();
+
+  // Helper function to recompute |state_info_.target_name| when
+  // it may have changed.  (If it's non-null it should be left alone,
+  // otherwise updated from |full_path_|.)
+  void UpdateTarget();
+
+  // State information used by the download manager.
+  DownloadStateInfo state_info_;
+
+  // The handle to the request information.  Used for operations outside the
+  // download system.
+  DownloadRequestHandle request_handle_;
+
+  // Download ID assigned by DownloadResourceHandler.
+  int32 download_id_;
+
+  // Full path to the downloaded or downloading file.
+  FilePath full_path_;
+
+  // A number that should be appended to the path to make it unique, or 0 if the
+  // path should be used as is.
+  int path_uniquifier_;
+
+  // The chain of redirects that leading up to and including the final URL.
+  std::vector<GURL> url_chain_;
+
+  // The URL of the page that initiated the download.
+  GURL referrer_url_;
+
+  // Suggested filename in 'download' attribute of an anchor. Details:
+  // http://www.whatwg.org/specs/web-apps/current-work/#downloading-hyperlinks
+  std::string suggested_filename_;
+
+  // Information from the request.
+  // Content-disposition field from the header.
+  std::string content_disposition_;
+
+  // Mime-type from the header.  Subject to change.
+  std::string mime_type_;
+
+  // The value of the content type header sent with the downloaded item.  It
+  // may be different from |mime_type_|, which may be set based on heuristics
+  // which may look at the file extension and first few bytes of the file.
+  std::string original_mime_type_;
+
+  // The charset of the referring page where the download request comes from.
+  // It's used to construct a suggested filename.
+  std::string referrer_charset_;
+
+  // Total bytes expected
+  int64 total_bytes_;
+
+  // Current received bytes
+  int64 received_bytes_;
+
+  // Last error.
+  int last_os_error_;
+
+  // Start time for calculating remaining time
+  base::TimeTicks start_tick_;
+
+  // The current state of this download
+  DownloadState state_;
+
+  // The views of this item in the download shelf and download tab
+  ObserverList<Observer> observers_;
+
+  // Time the download was started
+  base::Time start_time_;
+
+  // Our persistent store handle
+  int64 db_handle_;
+
+  // Timer for regularly updating our observers
+  base::RepeatingTimer<DownloadItem> update_timer_;
+
+  // Our owning object
+  DownloadManager* download_manager_;
+
+  // In progress downloads may be paused by the user, we note it here
+  bool is_paused_;
+
+  // A flag for indicating if the download should be opened at completion.
+  bool open_when_complete_;
+
+  // A flag for indicating if the downloaded file is externally removed.
+  bool file_externally_removed_;
+
+  // Indicates if the download is considered potentially safe or dangerous
+  // (executable files are typically considered dangerous).
+  SafetyState safety_state_;
+
+  // True if the download was auto-opened. We set this rather than using
+  // an observer as it's frequently possible for the download to be auto opened
+  // before the observer is added.
+  bool auto_opened_;
+
+  // True if the download was initiated in an incognito window.
+  bool is_otr_;
+
+  // True if the item was downloaded temporarily.
+  bool is_temporary_;
+
+  // True if we've saved all the data for the download.
+  bool all_data_saved_;
+
+  // Did the user open the item either directly or indirectly (such as by
+  // setting always open files of this type)? The shelf also sets this field
+  // when the user closes the shelf before the item has been opened but should
+  // be treated as though the user opened it.
+  bool opened_;
+
+  // Do we actual open downloads when requested?  For testing purposes
+  // only.
+  bool open_enabled_;
+
+  // DownloadItem observes CRX installs it initiates.
+  NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadItem);
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_H_
diff --git a/content/browser/download/download_manager.cc b/content/browser/download/download_manager.cc
new file mode 100644
index 0000000..32d504a
--- /dev/null
+++ b/content/browser/download/download_manager.cc
@@ -0,0 +1,1080 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_manager.h"
+
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/i18n/case_conversion.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/task.h"
+#include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_history.h"
+#include "chrome/browser/download/download_manager_delegate.h"
+#include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/history/download_history_info.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_file_manager.h"
+#include "content/browser/download/download_item.h"
+#include "content/browser/download/download_status_updater.h"
+#include "content/browser/renderer_host/render_process_host.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/renderer_host/resource_dispatcher_host.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/common/content_notification_types.h"
+#include "content/common/notification_service.h"
+
+DownloadManager::DownloadManager(DownloadManagerDelegate* delegate,
+                                 DownloadStatusUpdater* status_updater)
+    : shutdown_needed_(false),
+      profile_(NULL),
+      file_manager_(NULL),
+      status_updater_(status_updater->AsWeakPtr()),
+      next_save_page_id_(0),
+      delegate_(delegate) {
+  if (status_updater_)
+    status_updater_->AddDelegate(this);
+}
+
+DownloadManager::~DownloadManager() {
+  DCHECK(!shutdown_needed_);
+  if (status_updater_)
+    status_updater_->RemoveDelegate(this);
+}
+
+void DownloadManager::Shutdown() {
+  VLOG(20) << __FUNCTION__ << "()"
+           << " shutdown_needed_ = " << shutdown_needed_;
+  if (!shutdown_needed_)
+    return;
+  shutdown_needed_ = false;
+
+  FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown());
+
+  if (file_manager_) {
+    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+        NewRunnableMethod(file_manager_,
+                          &DownloadFileManager::OnDownloadManagerShutdown,
+                          make_scoped_refptr(this)));
+  }
+
+  AssertContainersConsistent();
+
+  // Go through all downloads in downloads_.  Dangerous ones we need to
+  // remove on disk, and in progress ones we need to cancel.
+  for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
+    DownloadItem* download = *it;
+
+    // Save iterator from potential erases in this set done by called code.
+    // Iterators after an erasure point are still valid for lists and
+    // associative containers such as sets.
+    it++;
+
+    if (download->safety_state() == DownloadItem::DANGEROUS &&
+        download->IsPartialDownload()) {
+      // The user hasn't accepted it, so we need to remove it
+      // from the disk.  This may or may not result in it being
+      // removed from the DownloadManager queues and deleted
+      // (specifically, DownloadManager::RemoveDownload only
+      // removes and deletes it if it's known to the history service)
+      // so the only thing we know after calling this function is that
+      // the download was deleted if-and-only-if it was removed
+      // from all queues.
+      download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
+    } else if (download->IsPartialDownload()) {
+      download->Cancel(false);
+      download_history_->UpdateEntry(download);
+    }
+  }
+
+  // At this point, all dangerous downloads have had their files removed
+  // and all in progress downloads have been cancelled.  We can now delete
+  // anything left.
+
+  // Copy downloads_ to separate container so as not to set off checks
+  // in DownloadItem destruction.
+  DownloadSet downloads_to_delete;
+  downloads_to_delete.swap(downloads_);
+
+  in_progress_.clear();
+  active_downloads_.clear();
+  history_downloads_.clear();
+  STLDeleteElements(&downloads_to_delete);
+
+  DCHECK(save_page_downloads_.empty());
+
+  file_manager_ = NULL;
+
+  download_history_.reset();
+  download_prefs_.reset();
+
+  shutdown_needed_ = false;
+}
+
+void DownloadManager::GetTemporaryDownloads(
+    const FilePath& dir_path, DownloadVector* result) {
+  DCHECK(result);
+
+  for (DownloadMap::iterator it = history_downloads_.begin();
+       it != history_downloads_.end(); ++it) {
+    if (it->second->is_temporary() &&
+        it->second->full_path().DirName() == dir_path)
+      result->push_back(it->second);
+  }
+}
+
+void DownloadManager::GetAllDownloads(
+    const FilePath& dir_path, DownloadVector* result) {
+  DCHECK(result);
+
+  for (DownloadMap::iterator it = history_downloads_.begin();
+       it != history_downloads_.end(); ++it) {
+    if (!it->second->is_temporary() &&
+        (dir_path.empty() || it->second->full_path().DirName() == dir_path))
+      result->push_back(it->second);
+  }
+}
+
+void DownloadManager::GetCurrentDownloads(
+    const FilePath& dir_path, DownloadVector* result) {
+  DCHECK(result);
+
+  for (DownloadMap::iterator it = history_downloads_.begin();
+       it != history_downloads_.end(); ++it) {
+    DownloadItem* item =it->second;
+    // Skip temporary items.
+    if (item->is_temporary())
+      continue;
+    // Skip items that have all their data, and are OK to save.
+    if (!item->IsPartialDownload() &&
+        (item->safety_state() != DownloadItem::DANGEROUS))
+      continue;
+    // Skip items that don't match |dir_path|.
+    // If |dir_path| is empty, all remaining items match.
+    if (!dir_path.empty() && (it->second->full_path().DirName() != dir_path))
+      continue;
+
+    result->push_back(item);
+  }
+
+  // If we have a parent profile, let it add its downloads to the results.
+  Profile* original_profile = profile_->GetOriginalProfile();
+  if (original_profile != profile_)
+    original_profile->GetDownloadManager()->GetCurrentDownloads(dir_path,
+                                                                result);
+}
+
+void DownloadManager::SearchDownloads(const string16& query,
+                                      DownloadVector* result) {
+  DCHECK(result);
+
+  string16 query_lower(base::i18n::ToLower(query));
+
+  for (DownloadMap::iterator it = history_downloads_.begin();
+       it != history_downloads_.end(); ++it) {
+    DownloadItem* download_item = it->second;
+
+    if (download_item->is_temporary() || download_item->is_extension_install())
+      continue;
+
+    // Display Incognito downloads only in Incognito window, and vice versa.
+    // The Incognito Downloads page will get the list of non-Incognito downloads
+    // from its parent profile.
+    if (profile_->IsOffTheRecord() != download_item->is_otr())
+      continue;
+
+    if (download_item->MatchesQuery(query_lower))
+      result->push_back(download_item);
+  }
+
+  // If we have a parent profile, let it add its downloads to the results.
+  Profile* original_profile = profile_->GetOriginalProfile();
+  if (original_profile != profile_)
+    original_profile->GetDownloadManager()->SearchDownloads(query, result);
+}
+
+// Query the history service for information about all persisted downloads.
+bool DownloadManager::Init(Profile* profile) {
+  DCHECK(profile);
+  DCHECK(!shutdown_needed_)  << "DownloadManager already initialized.";
+  shutdown_needed_ = true;
+
+  profile_ = profile;
+  download_history_.reset(new DownloadHistory(profile));
+  download_history_->Load(
+      NewCallback(this, &DownloadManager::OnQueryDownloadEntriesComplete));
+
+  download_prefs_.reset(new DownloadPrefs(profile_->GetPrefs()));
+
+  // In test mode, there may be no ResourceDispatcherHost.  In this case it's
+  // safe to avoid setting |file_manager_| because we only call a small set of
+  // functions, none of which need it.
+  ResourceDispatcherHost* rdh = g_browser_process->resource_dispatcher_host();
+  if (rdh) {
+    file_manager_ = rdh->download_file_manager();
+    DCHECK(file_manager_);
+  }
+
+  other_download_manager_observer_.reset(
+      new OtherDownloadManagerObserver(this));
+
+  return true;
+}
+
+// We have received a message from DownloadFileManager about a new download.
+void DownloadManager::StartDownload(int32 download_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (delegate_->ShouldStartDownload(download_id))
+    RestartDownload(download_id);
+}
+
+void DownloadManager::CheckForHistoryFilesRemoval() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  for (DownloadMap::iterator it = history_downloads_.begin();
+       it != history_downloads_.end(); ++it) {
+    CheckForFileRemoval(it->second);
+  }
+}
+
+void DownloadManager::CheckForFileRemoval(DownloadItem* download_item) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (download_item->IsComplete() &&
+      !download_item->file_externally_removed()) {
+    BrowserThread::PostTask(
+        BrowserThread::FILE, FROM_HERE,
+        NewRunnableMethod(this,
+                          &DownloadManager::CheckForFileRemovalOnFileThread,
+                          download_item->db_handle(),
+                          download_item->GetTargetFilePath()));
+  }
+}
+
+void DownloadManager::CheckForFileRemovalOnFileThread(
+    int64 db_handle, const FilePath& path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  if (!file_util::PathExists(path)) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        NewRunnableMethod(this,
+                          &DownloadManager::OnFileRemovalDetected,
+                          db_handle));
+  }
+}
+
+void DownloadManager::OnFileRemovalDetected(int64 db_handle) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DownloadMap::iterator it = history_downloads_.find(db_handle);
+  if (it != history_downloads_.end()) {
+    DownloadItem* download_item = it->second;
+    download_item->OnDownloadedFileRemoved();
+  }
+}
+
+void DownloadManager::RestartDownload(
+    int32 download_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DownloadItem* download = GetActiveDownloadItem(download_id);
+  if (!download)
+    return;
+
+  VLOG(20) << __FUNCTION__ << "()"
+           << " download = " << download->DebugString(true);
+
+  FilePath suggested_path = download->suggested_path();
+
+  if (download->prompt_user_for_save_location()) {
+    // We must ask the user for the place to put the download.
+    DownloadRequestHandle request_handle = download->request_handle();
+    TabContents* contents = request_handle.GetTabContents();
+
+    // |id_ptr| will be deleted in either FileSelected() or
+    // FileSelectionCancelled().
+    int32* id_ptr = new int32;
+    *id_ptr = download_id;
+
+    delegate_->ChooseDownloadPath(
+        contents, suggested_path, reinterpret_cast<void*>(id_ptr));
+
+    FOR_EACH_OBSERVER(Observer, observers_,
+                      SelectFileDialogDisplayed(download_id));
+  } else {
+    // No prompting for download, just continue with the suggested name.
+    ContinueDownloadWithPath(download, suggested_path);
+  }
+}
+
+void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DownloadItem* download = new DownloadItem(this, *info,
+                                            profile_->IsOffTheRecord());
+  int32 download_id = info->download_id;
+  DCHECK(!ContainsKey(in_progress_, download_id));
+  DCHECK(!ContainsKey(active_downloads_, download_id));
+  downloads_.insert(download);
+  active_downloads_[download_id] = download;
+}
+
+void DownloadManager::ContinueDownloadWithPath(DownloadItem* download,
+                                               const FilePath& chosen_file) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(download);
+
+  int32 download_id = download->id();
+
+  // NOTE(ahendrickson) Eventually |active_downloads_| will replace
+  // |in_progress_|, but we don't want to change the semantics yet.
+  DCHECK(!ContainsKey(in_progress_, download_id));
+  DCHECK(ContainsKey(downloads_, download));
+  DCHECK(ContainsKey(active_downloads_, download_id));
+
+  // Make sure the initial file name is set only once.
+  DCHECK(download->full_path().empty());
+  download->OnPathDetermined(chosen_file);
+
+  VLOG(20) << __FUNCTION__ << "()"
+           << " download = " << download->DebugString(true);
+
+  in_progress_[download_id] = download;
+  UpdateAppIcon();  // Reflect entry into in_progress_.
+
+  // Rename to intermediate name.
+  FilePath download_path;
+  if (download->IsDangerous()) {
+    // The download is not safe.  We can now rename the file to its
+    // tentative name using RenameInProgressDownloadFile.
+    // NOTE: The |Rename| below will be a no-op for dangerous files, as we're
+    // renaming it to the same name.
+    download_path = download->full_path();
+  } else {
+    // The download is a safe download.  We need to
+    // rename it to its intermediate '.crdownload' path.  The final
+    // name after user confirmation will be set from
+    // DownloadItem::OnDownloadCompleting.
+    download_path =
+        download_util::GetCrDownloadPath(download->full_path());
+  }
+
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      NewRunnableMethod(
+          file_manager_, &DownloadFileManager::RenameInProgressDownloadFile,
+          download->id(), download_path));
+
+  download->Rename(download_path);
+
+  download_history_->AddEntry(download,
+      NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete));
+}
+
+void DownloadManager::UpdateDownload(int32 download_id, int64 size) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DownloadMap::iterator it = active_downloads_.find(download_id);
+  if (it != active_downloads_.end()) {
+    DownloadItem* download = it->second;
+    if (download->IsInProgress()) {
+      download->Update(size);
+      UpdateAppIcon();  // Reflect size updates.
+      download_history_->UpdateEntry(download);
+    }
+  }
+}
+
+void DownloadManager::OnResponseCompleted(int32 download_id,
+                                          int64 size,
+                                          int os_error,
+                                          const std::string& hash) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  // ERR_CONNECTION_CLOSED is allowed since a number of servers in the wild
+  // advertise a larger Content-Length than the amount of bytes in the message
+  // body, and then close the connection. Other browsers - IE8, Firefox 4.0.1,
+  // and Safari 5.0.4 - treat the download as complete in this case, so we
+  // follow their lead.
+  if (os_error == 0 || os_error == net::ERR_CONNECTION_CLOSED) {
+    OnAllDataSaved(download_id, size, hash);
+  } else {
+    OnDownloadError(download_id, size, os_error);
+  }
+}
+
+void DownloadManager::OnAllDataSaved(int32 download_id,
+                                     int64 size,
+                                     const std::string& hash) {
+  VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
+           << " size = " << size;
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  // If it's not in active_downloads_, that means it was cancelled; just
+  // ignore the notification.
+  if (active_downloads_.count(download_id) == 0)
+    return;
+
+  DownloadItem* download = active_downloads_[download_id];
+  download->OnAllDataSaved(size);
+
+  MaybeCompleteDownload(download);
+}
+
+void DownloadManager::AssertQueueStateConsistent(DownloadItem* download) {
+  // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
+  if (download->state() == DownloadItem::REMOVING) {
+    CHECK(!ContainsKey(downloads_, download));
+    CHECK(!ContainsKey(active_downloads_, download->id()));
+    CHECK(!ContainsKey(in_progress_, download->id()));
+    CHECK(!ContainsKey(history_downloads_, download->db_handle()));
+    return;
+  }
+
+  // Should be in downloads_ if we're not REMOVING.
+  CHECK(ContainsKey(downloads_, download));
+
+  // Check history_downloads_ consistency.
+  if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
+    CHECK(ContainsKey(history_downloads_, download->db_handle()));
+  } else {
+    // TODO(rdsmith): Somewhat painful; make sure to disable in
+    // release builds after resolution of http://crbug.com/85408.
+    for (DownloadMap::iterator it = history_downloads_.begin();
+         it != history_downloads_.end(); ++it) {
+      CHECK(it->second != download);
+    }
+  }
+
+  CHECK(ContainsKey(active_downloads_, download->id()) ==
+        (download->state() == DownloadItem::IN_PROGRESS));
+  CHECK(ContainsKey(in_progress_, download->id()) ==
+        (download->state() == DownloadItem::IN_PROGRESS));
+}
+
+bool DownloadManager::IsDownloadReadyForCompletion(DownloadItem* download) {
+  // If we don't have all the data, the download is not ready for
+  // completion.
+  if (!download->all_data_saved())
+    return false;
+
+  // If the download is dangerous, but not yet validated, it's not ready for
+  // completion.
+  if (download->safety_state() == DownloadItem::DANGEROUS)
+    return false;
+
+  // If the download isn't active (e.g. has been cancelled) it's not
+  // ready for completion.
+  if (active_downloads_.count(download->id()) == 0)
+    return false;
+
+  // If the download hasn't been inserted into the history system
+  // (which occurs strictly after file name determination, intermediate
+  // file rename, and UI display) then it's not ready for completion.
+  if (download->db_handle() == DownloadHistory::kUninitializedHandle)
+    return false;
+
+  return true;
+}
+
+void DownloadManager::MaybeCompleteDownload(DownloadItem* download) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  VLOG(20) << __FUNCTION__ << "()" << " download = "
+           << download->DebugString(false);
+
+  if (!IsDownloadReadyForCompletion(download))
+    return;
+
+  // TODO(rdsmith): DCHECK that we only pass through this point
+  // once per download.  The natural way to do this is by a state
+  // transition on the DownloadItem.
+
+  // Confirm we're in the proper set of states to be here;
+  // in in_progress_, have all data, have a history handle, (validated or safe).
+  DCHECK_NE(DownloadItem::DANGEROUS, download->safety_state());
+  DCHECK_EQ(1u, in_progress_.count(download->id()));
+  DCHECK(download->all_data_saved());
+  DCHECK(download->db_handle() != DownloadHistory::kUninitializedHandle);
+  DCHECK_EQ(1u, history_downloads_.count(download->db_handle()));
+
+  VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
+           << download->DebugString(false);
+
+  // Remove the id from in_progress
+  in_progress_.erase(download->id());
+  UpdateAppIcon();  // Reflect removal from in_progress_.
+
+  download_history_->UpdateEntry(download);
+
+  // Finish the download.
+  download->OnDownloadCompleting(file_manager_);
+}
+
+void DownloadManager::DownloadCompleted(int32 download_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DownloadItem* download = GetDownloadItem(download_id);
+  DCHECK(download);
+  download_history_->UpdateEntry(download);
+  active_downloads_.erase(download_id);
+}
+
+void DownloadManager::OnDownloadRenamedToFinalName(int download_id,
+                                                   const FilePath& full_path,
+                                                   int uniquifier) {
+  VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
+           << " full_path = \"" << full_path.value() << "\""
+           << " uniquifier = " << uniquifier;
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DownloadItem* item = GetDownloadItem(download_id);
+  if (!item)
+    return;
+
+  if (item->safety_state() == DownloadItem::SAFE) {
+    DCHECK_EQ(0, uniquifier) << "We should not uniquify SAFE downloads twice";
+  }
+
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      NewRunnableMethod(
+          file_manager_, &DownloadFileManager::CompleteDownload, download_id));
+
+  if (uniquifier)
+    item->set_path_uniquifier(uniquifier);
+
+  item->OnDownloadRenamedToFinalName(full_path);
+  download_history_->UpdateDownloadPath(item, full_path);
+}
+
+void DownloadManager::DownloadCancelled(int32 download_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DownloadMap::iterator it = in_progress_.find(download_id);
+  if (it == in_progress_.end())
+    return;
+  DownloadItem* download = it->second;
+
+  VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
+           << " download = " << download->DebugString(true);
+
+  // Clean up will happen when the history system create callback runs if we
+  // don't have a valid db_handle yet.
+  if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
+    in_progress_.erase(it);
+    active_downloads_.erase(download_id);
+    UpdateAppIcon();  // Reflect removal from in_progress_.
+    download_history_->UpdateEntry(download);
+  }
+
+  DownloadCancelledInternal(download_id, download->request_handle());
+}
+
+void DownloadManager::DownloadCancelledInternal(
+    int download_id, const DownloadRequestHandle& request_handle) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  request_handle.CancelRequest();
+
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      NewRunnableMethod(
+          file_manager_, &DownloadFileManager::CancelDownload, download_id));
+}
+
+void DownloadManager::OnDownloadError(int32 download_id,
+                                      int64 size,
+                                      int os_error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DownloadMap::iterator it = active_downloads_.find(download_id);
+  // A cancel at the right time could remove the download from the
+  // |active_downloads_| map before we get here.
+  if (it == active_downloads_.end())
+    return;
+
+  DownloadItem* download = it->second;
+
+  VLOG(20) << __FUNCTION__ << "()" << " Error " << os_error
+           << " at offset " << download->received_bytes()
+           << " for download = " << download->DebugString(true);
+
+  download->Interrupted(size, os_error);
+
+  // TODO(ahendrickson) - Remove this when we add resuming of interrupted
+  // downloads, as we will keep the download item around in that case.
+  //
+  // Clean up will happen when the history system create callback runs if we
+  // don't have a valid db_handle yet.
+  if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
+    in_progress_.erase(download_id);
+    active_downloads_.erase(download_id);
+    UpdateAppIcon();  // Reflect removal from in_progress_.
+    download_history_->UpdateEntry(download);
+  }
+
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      NewRunnableMethod(
+          file_manager_, &DownloadFileManager::CancelDownload, download_id));
+}
+
+void DownloadManager::UpdateAppIcon() {
+  if (status_updater_)
+    status_updater_->Update();
+}
+
+int DownloadManager::RemoveDownloadItems(
+    const DownloadVector& pending_deletes) {
+  if (pending_deletes.empty())
+    return 0;
+
+  // Delete from internal maps.
+  for (DownloadVector::const_iterator it = pending_deletes.begin();
+      it != pending_deletes.end();
+      ++it) {
+    DownloadItem* download = *it;
+    DCHECK(download);
+    history_downloads_.erase(download->db_handle());
+    save_page_downloads_.erase(download->id());
+    downloads_.erase(download);
+  }
+
+  // Tell observers to refresh their views.
+  NotifyModelChanged();
+
+  // Delete the download items themselves.
+  const int num_deleted = static_cast<int>(pending_deletes.size());
+  STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
+  return num_deleted;
+}
+
+void DownloadManager::RemoveDownload(int64 download_handle) {
+  DownloadMap::iterator it = history_downloads_.find(download_handle);
+  if (it == history_downloads_.end())
+    return;
+
+  // Make history update.
+  DownloadItem* download = it->second;
+  download_history_->RemoveEntry(download);
+
+  // Remove from our tables and delete.
+  int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
+  DCHECK_EQ(1, downloads_count);
+}
+
+int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
+                                            const base::Time remove_end) {
+  download_history_->RemoveEntriesBetween(remove_begin, remove_end);
+
+  // All downloads visible to the user will be in the history,
+  // so scan that map.
+  DownloadVector pending_deletes;
+  for (DownloadMap::const_iterator it = history_downloads_.begin();
+      it != history_downloads_.end();
+      ++it) {
+    DownloadItem* download = it->second;
+    if (download->start_time() >= remove_begin &&
+        (remove_end.is_null() || download->start_time() < remove_end) &&
+        (download->IsComplete() || download->IsCancelled())) {
+      AssertQueueStateConsistent(download);
+      pending_deletes.push_back(download);
+    }
+  }
+  return RemoveDownloadItems(pending_deletes);
+}
+
+int DownloadManager::RemoveDownloads(const base::Time remove_begin) {
+  return RemoveDownloadsBetween(remove_begin, base::Time());
+}
+
+int DownloadManager::RemoveAllDownloads() {
+  if (this != profile_->GetOriginalProfile()->GetDownloadManager()) {
+    // This is an incognito downloader. Clear All should clear main download
+    // manager as well.
+    profile_->GetOriginalProfile()->GetDownloadManager()->RemoveAllDownloads();
+  }
+  // The null times make the date range unbounded.
+  return RemoveDownloadsBetween(base::Time(), base::Time());
+}
+
+// Initiate a download of a specific URL. We send the request to the
+// ResourceDispatcherHost, and let it send us responses like a regular
+// download.
+void DownloadManager::DownloadUrl(const GURL& url,
+                                  const GURL& referrer,
+                                  const std::string& referrer_charset,
+                                  TabContents* tab_contents) {
+  DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(),
+                    tab_contents);
+}
+
+void DownloadManager::DownloadUrlToFile(const GURL& url,
+                                        const GURL& referrer,
+                                        const std::string& referrer_charset,
+                                        const DownloadSaveInfo& save_info,
+                                        TabContents* tab_contents) {
+  DCHECK(tab_contents);
+  // We send a pointer to content::ResourceContext, instead of the usual
+  // reference, so that a copy of the object isn't made.
+  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+      NewRunnableFunction(&download_util::DownloadUrl,
+                          url,
+                          referrer,
+                          referrer_charset,
+                          save_info,
+                          g_browser_process->resource_dispatcher_host(),
+                          tab_contents->GetRenderProcessHost()->id(),
+                          tab_contents->render_view_host()->routing_id(),
+                          &tab_contents->browser_context()->
+                              GetResourceContext()));
+}
+
+void DownloadManager::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+  observer->ModelChanged();
+}
+
+void DownloadManager::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool DownloadManager::IsDownloadProgressKnown() {
+  for (DownloadMap::iterator i = in_progress_.begin();
+       i != in_progress_.end(); ++i) {
+    if (i->second->total_bytes() <= 0)
+      return false;
+  }
+
+  return true;
+}
+
+int64 DownloadManager::GetInProgressDownloadCount() {
+  return in_progress_.size();
+}
+
+int64 DownloadManager::GetReceivedDownloadBytes() {
+  DCHECK(IsDownloadProgressKnown());
+  int64 received_bytes = 0;
+  for (DownloadMap::iterator i = in_progress_.begin();
+       i != in_progress_.end(); ++i) {
+    received_bytes += i->second->received_bytes();
+  }
+  return received_bytes;
+}
+
+int64 DownloadManager::GetTotalDownloadBytes() {
+  DCHECK(IsDownloadProgressKnown());
+  int64 total_bytes = 0;
+  for (DownloadMap::iterator i = in_progress_.begin();
+       i != in_progress_.end(); ++i) {
+    total_bytes += i->second->total_bytes();
+  }
+  return total_bytes;
+}
+
+void DownloadManager::FileSelected(const FilePath& path, void* params) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  int32* id_ptr = reinterpret_cast<int32*>(params);
+  DCHECK(id_ptr != NULL);
+  int32 download_id = *id_ptr;
+  delete id_ptr;
+
+  DownloadItem* download = GetActiveDownloadItem(download_id);
+  if (!download)
+    return;
+  VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
+            << " download = " << download->DebugString(true);
+
+  if (download->prompt_user_for_save_location())
+    last_download_path_ = path.DirName();
+
+  // Make sure the initial file name is set only once.
+  ContinueDownloadWithPath(download, path);
+}
+
+void DownloadManager::FileSelectionCanceled(void* params) {
+  // The user didn't pick a place to save the file, so need to cancel the
+  // download that's already in progress to the temporary location.
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  int32* id_ptr = reinterpret_cast<int32*>(params);
+  DCHECK(id_ptr != NULL);
+  int32 download_id = *id_ptr;
+  delete id_ptr;
+
+  DownloadItem* download = GetActiveDownloadItem(download_id);
+  if (!download)
+    return;
+
+  VLOG(20) << __FUNCTION__ << "()"
+           << " download = " << download->DebugString(true);
+
+  DownloadCancelledInternal(download_id, download->request_handle());
+}
+
+// Operations posted to us from the history service ----------------------------
+
+// The history service has retrieved all download entries. 'entries' contains
+// 'DownloadHistoryInfo's in sorted order (by ascending start_time).
+void DownloadManager::OnQueryDownloadEntriesComplete(
+    std::vector<DownloadHistoryInfo>* entries) {
+  for (size_t i = 0; i < entries->size(); ++i) {
+    DownloadItem* download = new DownloadItem(this, entries->at(i));
+    DCHECK(!ContainsKey(history_downloads_, download->db_handle()));
+    downloads_.insert(download);
+    history_downloads_[download->db_handle()] = download;
+    VLOG(20) << __FUNCTION__ << "()" << i << ">"
+             << " download = " << download->DebugString(true);
+  }
+  NotifyModelChanged();
+  CheckForHistoryFilesRemoval();
+}
+
+void DownloadManager::AddDownloadItemToHistory(DownloadItem* download,
+                                               int64 db_handle) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  // It's not immediately obvious, but HistoryBackend::CreateDownload() can
+  // call this function with an invalid |db_handle|. For instance, this can
+  // happen when the history database is offline. We cannot have multiple
+  // DownloadItems with the same invalid db_handle, so we need to assign a
+  // unique |db_handle| here.
+  if (db_handle == DownloadHistory::kUninitializedHandle)
+    db_handle = download_history_->GetNextFakeDbHandle();
+
+  // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508
+  // is fixed.
+  CHECK_NE(DownloadHistory::kUninitializedHandle, db_handle);
+
+  DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle);
+  download->set_db_handle(db_handle);
+
+  DCHECK(!ContainsKey(history_downloads_, download->db_handle()));
+  history_downloads_[download->db_handle()] = download;
+
+  // Show in the appropriate browser UI.
+  // This includes buttons to save or cancel, for a dangerous download.
+  ShowDownloadInBrowser(download);
+
+  // Inform interested objects about the new download.
+  NotifyModelChanged();
+}
+
+// Once the new DownloadItem's creation info has been committed to the history
+// service, we associate the DownloadItem with the db handle, update our
+// 'history_downloads_' map and inform observers.
+void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id,
+                                                    int64 db_handle) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DownloadItem* download = GetActiveDownloadItem(download_id);
+  if (!download)
+    return;
+
+  VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
+           << " download_id = " << download_id
+           << " download = " << download->DebugString(true);
+
+  AddDownloadItemToHistory(download, db_handle);
+
+  // If the download is still in progress, try to complete it.
+  //
+  // Otherwise, download has been cancelled or interrupted before we've
+  // received the DB handle.  We post one final message to the history
+  // service so that it can be properly in sync with the DownloadItem's
+  // completion status, and also inform any observers so that they get
+  // more than just the start notification.
+  if (download->IsInProgress()) {
+    MaybeCompleteDownload(download);
+  } else {
+    DCHECK(download->IsCancelled())
+        << " download = " << download->DebugString(true);
+    in_progress_.erase(download_id);
+    active_downloads_.erase(download_id);
+    download_history_->UpdateEntry(download);
+    download->UpdateObservers();
+  }
+}
+
+void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) {
+  // The 'contents' may no longer exist if the user closed the tab before we
+  // get this start completion event.
+  DownloadRequestHandle request_handle = download->request_handle();
+  TabContents* content = request_handle.GetTabContents();
+
+  // If the contents no longer exists, we ask the embedder to suggest another
+  // tab.
+  if (!content)
+    content = delegate_->GetAlternativeTabContentsToNotifyForDownload();
+
+  if (content)
+    content->OnStartDownload(download);
+}
+
+// Clears the last download path, used to initialize "save as" dialogs.
+void DownloadManager::ClearLastDownloadPath() {
+  last_download_path_ = FilePath();
+}
+
+void DownloadManager::NotifyModelChanged() {
+  FOR_EACH_OBSERVER(Observer, observers_, ModelChanged());
+}
+
+DownloadItem* DownloadManager::GetDownloadItem(int download_id) {
+  // The |history_downloads_| map is indexed by the download's db_handle,
+  // not its id, so we have to iterate.
+  for (DownloadMap::iterator it = history_downloads_.begin();
+       it != history_downloads_.end(); ++it) {
+    DownloadItem* item = it->second;
+    if (item->id() == download_id)
+      return item;
+  }
+  return NULL;
+}
+
+DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) {
+  DCHECK(ContainsKey(active_downloads_, download_id));
+  DownloadItem* download = active_downloads_[download_id];
+  DCHECK(download != NULL);
+  return download;
+}
+
+// Confirm that everything in all maps is also in |downloads_|, and that
+// everything in |downloads_| is also in some other map.
+void DownloadManager::AssertContainersConsistent() const {
+#if !defined(NDEBUG)
+  // Turn everything into sets.
+  const DownloadMap* input_maps[] = {&active_downloads_,
+                                     &history_downloads_,
+                                     &save_page_downloads_};
+  DownloadSet active_set, history_set, save_page_set;
+  DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
+  DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
+    for (DownloadMap::const_iterator it = input_maps[i]->begin();
+         it != input_maps[i]->end(); ++it) {
+      all_sets[i]->insert(&*it->second);
+    }
+  }
+
+  // Check if each set is fully present in downloads, and create a union.
+  DownloadSet downloads_union;
+  for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
+    DownloadSet remainder;
+    std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
+    std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
+                        downloads_.begin(), downloads_.end(),
+                        insert_it);
+    DCHECK(remainder.empty());
+    std::insert_iterator<DownloadSet>
+        insert_union(downloads_union, downloads_union.end());
+    std::set_union(downloads_union.begin(), downloads_union.end(),
+                   all_sets[i]->begin(), all_sets[i]->end(),
+                   insert_union);
+  }
+
+  // Is everything in downloads_ present in one of the other sets?
+  DownloadSet remainder;
+  std::insert_iterator<DownloadSet>
+      insert_remainder(remainder, remainder.begin());
+  std::set_difference(downloads_.begin(), downloads_.end(),
+                      downloads_union.begin(), downloads_union.end(),
+                      insert_remainder);
+  DCHECK(remainder.empty());
+#endif
+}
+
+// DownloadManager::OtherDownloadManagerObserver implementation ----------------
+
+DownloadManager::OtherDownloadManagerObserver::OtherDownloadManagerObserver(
+    DownloadManager* observing_download_manager)
+    : observing_download_manager_(observing_download_manager),
+      observed_download_manager_(NULL) {
+  if (observing_download_manager->profile_->GetOriginalProfile() ==
+      observing_download_manager->profile_) {
+    return;
+  }
+
+  observed_download_manager_ = observing_download_manager_->
+      profile_->GetOriginalProfile()->GetDownloadManager();
+  observed_download_manager_->AddObserver(this);
+}
+
+DownloadManager::OtherDownloadManagerObserver::~OtherDownloadManagerObserver() {
+  if (observed_download_manager_)
+    observed_download_manager_->RemoveObserver(this);
+}
+
+void DownloadManager::OtherDownloadManagerObserver::ModelChanged() {
+  observing_download_manager_->NotifyModelChanged();
+}
+
+void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() {
+  observed_download_manager_ = NULL;
+}
+
+void DownloadManager::SavePageDownloadStarted(DownloadItem* download) {
+  DCHECK(!ContainsKey(save_page_downloads_, download->id()));
+  downloads_.insert(download);
+  save_page_downloads_[download->id()] = download;
+
+  // Add this entry to the history service.
+  // Additionally, the UI is notified in the callback.
+  download_history_->AddEntry(download,
+      NewCallback(this, &DownloadManager::OnSavePageDownloadEntryAdded));
+}
+
+// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
+// The history callback will call OnSavePageDownloadEntryAdded.
+// If the download finishes before the history callback,
+// OnSavePageDownloadEntryAdded calls SavePageDownloadFinished, ensuring that
+// the history event is update regardless of the order in which these two events
+// complete.
+// If something removes the download item from the download manager (Remove,
+// Shutdown) the result will be that the SavePage system will not be able to
+// properly update the download item (which no longer exists) or the download
+// history, but the action will complete properly anyway.  This may lead to the
+// history entry being wrong on a reload of chrome (specifically in the case of
+// Initiation -> History Callback -> Removal -> Completion), but there's no way
+// to solve that without canceling on Remove (which would then update the DB).
+
+void DownloadManager::OnSavePageDownloadEntryAdded(int32 download_id,
+                                                   int64 db_handle) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
+  // This can happen if the download manager is shutting down and all maps
+  // have been cleared.
+  if (it == save_page_downloads_.end())
+    return;
+
+  DownloadItem* download = it->second;
+  if (!download) {
+    NOTREACHED();
+    return;
+  }
+
+  AddDownloadItemToHistory(download, db_handle);
+
+  // Finalize this download if it finished before the history callback.
+  if (!download->IsInProgress())
+    SavePageDownloadFinished(download);
+}
+
+void DownloadManager::SavePageDownloadFinished(DownloadItem* download) {
+  if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
+    download_history_->UpdateEntry(download);
+    DCHECK(ContainsKey(save_page_downloads_, download->id()));
+    save_page_downloads_.erase(download->id());
+
+    if (download->IsComplete())
+      NotificationService::current()->Notify(
+          content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
+          Source<DownloadManager>(this),
+          Details<DownloadItem>(download));
+  }
+}
+
+int32 DownloadManager::GetNextSavePageId() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  return next_save_page_id_++;
+}
+
diff --git a/content/browser/download/download_manager.h b/content/browser/download/download_manager.h
new file mode 100644
index 0000000..ee9d4d74
--- /dev/null
+++ b/content/browser/download/download_manager.h
@@ -0,0 +1,418 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The DownloadManager object manages the process of downloading, including
+// updates to the history system and providing the information for displaying
+// the downloads view in the Destinations tab. There is one DownloadManager per
+// active profile in Chrome.
+//
+// Download observers:
+// Objects that are interested in notifications about new downloads, or progress
+// updates for a given download must implement one of the download observer
+// interfaces:
+//   DownloadManager::Observer:
+//     - allows observers, primarily views, to be notified when changes to the
+//       set of all downloads (such as new downloads, or deletes) occur
+// Use AddObserver() / RemoveObserver() on the appropriate download object to
+// receive state updates.
+//
+// Download state persistence:
+// The DownloadManager uses the history service for storing persistent
+// information about the state of all downloads. The history system maintains a
+// separate table for this called 'downloads'. At the point that the
+// DownloadManager is constructed, we query the history service for the state of
+// all persisted downloads.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/time.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/download/download_item.h"
+#include "content/browser/download/download_request_handle.h"
+#include "content/browser/download/download_status_updater_delegate.h"
+
+class DownloadFileManager;
+class DownloadHistory;
+class DownloadManagerDelegate;
+class DownloadPrefs;
+class DownloadStatusUpdater;
+class GURL;
+class Profile;
+class ResourceDispatcherHost;
+class TabContents;
+struct DownloadCreateInfo;
+struct DownloadHistoryInfo;
+struct DownloadSaveInfo;
+
+// Browser's download manager: manages all downloads and destination view.
+class DownloadManager
+    : public base::RefCountedThreadSafe<DownloadManager,
+                                        BrowserThread::DeleteOnUIThread>,
+      public DownloadStatusUpdaterDelegate {
+ public:
+  DownloadManager(DownloadManagerDelegate* delegate,
+                  DownloadStatusUpdater* status_updater);
+
+  // Shutdown the download manager. Must be called before destruction.
+  void Shutdown();
+
+  // Interface to implement for observers that wish to be informed of changes
+  // to the DownloadManager's collection of downloads.
+  class Observer {
+   public:
+    // New or deleted download, observers should query us for the current set
+    // of downloads.
+    virtual void ModelChanged() = 0;
+
+    // Called when the DownloadManager is being destroyed to prevent Observers
+    // from calling back to a stale pointer.
+    virtual void ManagerGoingDown() {}
+
+    // Called immediately after the DownloadManager puts up a select file
+    // dialog.
+    // |id| indicates which download opened the dialog.
+    virtual void SelectFileDialogDisplayed(int32 id) {}
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  typedef std::vector<DownloadItem*> DownloadVector;
+
+  // Return all temporary downloads that reside in the specified directory.
+  void GetTemporaryDownloads(const FilePath& dir_path, DownloadVector* result);
+
+  // Return all non-temporary downloads in the specified directory that are
+  // are in progress or have completed.
+  void GetAllDownloads(const FilePath& dir_path, DownloadVector* result);
+
+  // Return all non-temporary downloads in the specified directory that are
+  // in-progress (including dangerous downloads waiting for user confirmation).
+  void GetCurrentDownloads(const FilePath& dir_path, DownloadVector* result);
+
+  // Returns all non-temporary downloads matching |query|. Empty query matches
+  // everything.
+  void SearchDownloads(const string16& query, DownloadVector* result);
+
+  // Returns true if initialized properly.
+  bool Init(Profile* profile);
+
+  // Notifications sent from the download thread to the UI thread
+  void StartDownload(int32 id);
+  void UpdateDownload(int32 download_id, int64 size);
+  // |hash| is sha256 hash for the downloaded file. It is empty when the hash
+  // is not available.
+  void OnResponseCompleted(int32 download_id, int64 size, int os_error,
+                           const std::string& hash);
+
+  // Called from a view when a user clicks a UI button or link.
+  void DownloadCancelled(int32 download_id);
+  void RemoveDownload(int64 download_handle);
+
+  // Determine if the download is ready for completion, i.e. has had
+  // all data saved, and completed the filename determination and
+  // history insertion.
+  bool IsDownloadReadyForCompletion(DownloadItem* download);
+
+  // If all pre-requisites have been met, complete download processing, i.e.
+  // do internal cleanup, file rename, and potentially auto-open.
+  // (Dangerous downloads still may block on user acceptance after this
+  // point.)
+  void MaybeCompleteDownload(DownloadItem* download);
+
+  // Called when the download is renamed to its final name.
+  // |uniquifier| is a number used to make unique names for the file.  It is
+  // only valid for the DANGEROUS_BUT_VALIDATED state of the download item.
+  void OnDownloadRenamedToFinalName(int download_id,
+                                    const FilePath& full_path,
+                                    int uniquifier);
+
+  // Remove downloads after remove_begin (inclusive) and before remove_end
+  // (exclusive). You may pass in null Time values to do an unbounded delete
+  // in either direction.
+  int RemoveDownloadsBetween(const base::Time remove_begin,
+                             const base::Time remove_end);
+
+  // Remove downloads will delete all downloads that have a timestamp that is
+  // the same or more recent than |remove_begin|. The number of downloads
+  // deleted is returned back to the caller.
+  int RemoveDownloads(const base::Time remove_begin);
+
+  // Remove all downloads will delete all downloads. The number of downloads
+  // deleted is returned back to the caller.
+  int RemoveAllDownloads();
+
+  // Final download manager transition for download: Update the download
+  // history and remove the download from |active_downloads_|.
+  void DownloadCompleted(int32 download_id);
+
+  // Download the object at the URL. Used in cases such as "Save Link As..."
+  void DownloadUrl(const GURL& url,
+                   const GURL& referrer,
+                   const std::string& referrer_encoding,
+                   TabContents* tab_contents);
+
+  // Download the object at the URL and save it to the specified path. The
+  // download is treated as the temporary download and thus will not appear
+  // in the download history. Used in cases such as drag and drop.
+  void DownloadUrlToFile(const GURL& url,
+                         const GURL& referrer,
+                         const std::string& referrer_encoding,
+                         const DownloadSaveInfo& save_info,
+                         TabContents* tab_contents);
+
+  // Allow objects to observe the download creation process.
+  void AddObserver(Observer* observer);
+
+  // Remove a download observer from ourself.
+  void RemoveObserver(Observer* observer);
+
+  // Methods called on completion of a query sent to the history system.
+  void OnQueryDownloadEntriesComplete(
+      std::vector<DownloadHistoryInfo>* entries);
+  void OnCreateDownloadEntryComplete(int32 download_id, int64 db_handle);
+
+  // Display a new download in the appropriate browser UI.
+  void ShowDownloadInBrowser(DownloadItem* download);
+
+  // The number of in progress (including paused) downloads.
+  int in_progress_count() const {
+    return static_cast<int>(in_progress_.size());
+  }
+
+  Profile* profile() { return profile_; }
+
+  DownloadHistory* download_history() { return download_history_.get(); }
+
+  DownloadPrefs* download_prefs() { return download_prefs_.get(); }
+
+  FilePath last_download_path() { return last_download_path_; }
+
+  // Creates the download item.  Must be called on the UI thread.
+  void CreateDownloadItem(DownloadCreateInfo* info);
+
+  // Clears the last download path, used to initialize "save as" dialogs.
+  void ClearLastDownloadPath();
+
+  // Overridden from DownloadStatusUpdaterDelegate:
+  virtual bool IsDownloadProgressKnown();
+  virtual int64 GetInProgressDownloadCount();
+  virtual int64 GetReceivedDownloadBytes();
+  virtual int64 GetTotalDownloadBytes();
+
+  // Called by the delegate after the save as dialog is closed.
+  void FileSelected(const FilePath& path, void* params);
+  void FileSelectionCanceled(void* params);
+
+  // Called by the delegate if it delayed the download in
+  // DownloadManagerDelegate::ShouldStartDownload and now is ready.
+  void RestartDownload(int32 download_id);
+
+  // Checks whether downloaded files still exist. Updates state of downloads
+  // that refer to removed files. The check runs in the background and may
+  // finish asynchronously after this method returns.
+  void CheckForHistoryFilesRemoval();
+
+  // Checks whether a downloaded file still exists and updates the file's state
+  // if the file is already removed. The check runs in the background and may
+  // finish asynchronously after this method returns.
+  void CheckForFileRemoval(DownloadItem* download_item);
+
+  // Assert the named download item is on the correct queues
+  // in the DownloadManager.  For debugging.
+  void AssertQueueStateConsistent(DownloadItem* download);
+
+  // Get the download item from the history map.  Useful after the item has
+  // been removed from the active map, or was retrieved from the history DB.
+  DownloadItem* GetDownloadItem(int id);
+
+  // Called when Save Page download starts. Transfers ownership of |download|
+  // to the DownloadManager.
+  void SavePageDownloadStarted(DownloadItem* download);
+
+  // Callback when Save Page As entry is commited to the history system.
+  void OnSavePageDownloadEntryAdded(int32 download_id, int64 db_handle);
+
+  // Called when Save Page download is done.
+  void SavePageDownloadFinished(DownloadItem* download);
+
+  // Download Id for next Save Page.
+  int32 GetNextSavePageId();
+
+  // Get the download item from the active map.  Useful when the item is not
+  // yet in the history map.
+  DownloadItem* GetActiveDownloadItem(int id);
+
+  DownloadManagerDelegate* delegate() const { return delegate_; }
+
+ private:
+  typedef std::set<DownloadItem*> DownloadSet;
+  typedef base::hash_map<int64, DownloadItem*> DownloadMap;
+
+  // For testing.
+  friend class DownloadManagerTest;
+  friend class MockDownloadManager;
+
+  // This class is used to let an incognito DownloadManager observe changes to
+  // a normal DownloadManager, to propagate ModelChanged() calls from the parent
+  // DownloadManager to the observers of the incognito DownloadManager.
+  class OtherDownloadManagerObserver : public Observer {
+   public:
+    explicit OtherDownloadManagerObserver(
+        DownloadManager* observing_download_manager);
+    virtual ~OtherDownloadManagerObserver();
+
+    // Observer interface.
+    virtual void ModelChanged();
+    virtual void ManagerGoingDown();
+
+   private:
+    // The incognito download manager.
+    DownloadManager* observing_download_manager_;
+
+    // The original profile's download manager.
+    DownloadManager* observed_download_manager_;
+  };
+
+  friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
+  friend class DeleteTask<DownloadManager>;
+  friend class OtherDownloadManagerObserver;
+
+  virtual ~DownloadManager();
+
+  // Called on the FILE thread to check the existence of a downloaded file.
+  void CheckForFileRemovalOnFileThread(int64 db_handle, const FilePath& path);
+
+  // Called on the UI thread if the FILE thread detects the removal of
+  // the downloaded file. The UI thread updates the state of the file
+  // and then notifies this update to the file's observer.
+  void OnFileRemovalDetected(int64 db_handle);
+
+  // Called back after a target path for the file to be downloaded to has been
+  // determined, either automatically based on the suggested file name, or by
+  // the user in a Save As dialog box.
+  void ContinueDownloadWithPath(DownloadItem* download,
+                                const FilePath& chosen_file);
+
+  // Download cancel helper function.
+  void DownloadCancelledInternal(int download_id,
+                                 const DownloadRequestHandle& request_handle);
+
+  // All data has been downloaded.
+  // |hash| is sha256 hash for the downloaded file. It is empty when the hash
+  // is not available.
+  void OnAllDataSaved(int32 download_id, int64 size, const std::string& hash);
+
+  // An error occurred in the download.
+  void OnDownloadError(int32 download_id, int64 size, int os_error);
+
+  // Updates the app icon about the overall download progress.
+  void UpdateAppIcon();
+
+  // Inform observers that the model has changed.
+  void NotifyModelChanged();
+
+  // Debugging routine to confirm relationship between below
+  // containers; no-op if NDEBUG.
+  void AssertContainersConsistent() const;
+
+  // Add a DownloadItem to history_downloads_.
+  void AddDownloadItemToHistory(DownloadItem* item, int64 db_handle);
+
+  // Remove from internal maps.
+  int RemoveDownloadItems(const DownloadVector& pending_deletes);
+
+  // |downloads_| is the owning set for all downloads known to the
+  // DownloadManager.  This includes downloads started by the user in
+  // this session, downloads initialized from the history system, and
+  // "save page as" downloads.  All other DownloadItem containers in
+  // the DownloadManager are maps; they do not own the DownloadItems.
+  // Note that this is the only place (with any functional implications;
+  // see save_page_as_downloads_ below) that "save page as" downloads are
+  // kept, as the DownloadManager's only job is to hold onto those
+  // until destruction.
+  //
+  // |history_downloads_| is map of all downloads in this profile. The key
+  // is the handle returned by the history system, which is unique
+  // across sessions.
+  //
+  // |active_downloads_| is a map of all downloads that are currently being
+  // processed. The key is the ID assigned by the ResourceDispatcherHost,
+  // which is unique for the current session.
+  //
+  // |in_progress_| is a map of all downloads that are in progress and that have
+  // not yet received a valid history handle. The key is the ID assigned by the
+  // ResourceDispatcherHost, which is unique for the current session.
+  //
+  // |save_page_as_downloads_| (if defined) is a collection of all the
+  // downloads the "save page as" system has given to us to hold onto
+  // until we are destroyed.  It is only used for debugging.
+  //
+  // When a download is created through a user action, the corresponding
+  // DownloadItem* is placed in |active_downloads_| and remains there until the
+  // download is in a terminal state (COMPLETE or CANCELLED).  It is also
+  // placed in |in_progress_| and remains there until it has received a
+  // valid handle from the history system. Once it has a valid handle, the
+  // DownloadItem* is placed in the |history_downloads_| map.  When the
+  // download reaches a terminal state, it is removed from |in_progress_|.
+  // Downloads from past sessions read from a persisted state from the
+  // history system are placed directly into |history_downloads_| since
+  // they have valid handles in the history system.
+
+  DownloadSet downloads_;
+  DownloadMap history_downloads_;
+  DownloadMap in_progress_;
+  DownloadMap active_downloads_;
+  DownloadMap save_page_downloads_;
+
+  // True if the download manager has been initialized and requires a shutdown.
+  bool shutdown_needed_;
+
+  // Observers that want to be notified of changes to the set of downloads.
+  ObserverList<Observer> observers_;
+
+  // The current active profile.
+  Profile* profile_;
+
+  scoped_ptr<DownloadHistory> download_history_;
+
+  scoped_ptr<DownloadPrefs> download_prefs_;
+
+  // Non-owning pointer for handling file writing on the download_thread_.
+  DownloadFileManager* file_manager_;
+
+  // Non-owning pointer for updating the download status.
+  base::WeakPtr<DownloadStatusUpdater> status_updater_;
+
+  // The user's last choice for download directory. This is only used when the
+  // user wants us to prompt for a save location for each download.
+  FilePath last_download_path_;
+
+  // Download Id for next Save Page.
+  int32 next_save_page_id_;
+
+  scoped_ptr<OtherDownloadManagerObserver> other_download_manager_observer_;
+
+  // Allows an embedder to control behavior. Guaranteed to outlive this object.
+  DownloadManagerDelegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadManager);
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_
diff --git a/content/browser/download/download_request_handle.cc b/content/browser/download/download_request_handle.cc
new file mode 100644
index 0000000..83b0df60
--- /dev/null
+++ b/content/browser/download/download_request_handle.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_request_handle.h"
+
+#include "base/stringprintf.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_util.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/renderer_host/resource_dispatcher_host.h"
+#include "content/browser/tab_contents/tab_contents.h"
+
+// IO Thread indirections to resource dispatcher host.
+// Provided as targets for PostTask from within this object
+// only.
+static void ResourceDispatcherHostPauseRequest(
+    ResourceDispatcherHost* rdh,
+    int process_unique_id,
+    int request_id,
+    bool pause) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  rdh->PauseRequest(process_unique_id, request_id, pause);
+}
+
+static void ResourceDispatcherHostCancelRequest(
+    ResourceDispatcherHost* rdh,
+    int process_unique_id,
+    int request_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  rdh->CancelRequest(process_unique_id, request_id, false);
+}
+
+DownloadRequestHandle::DownloadRequestHandle()
+    : rdh_(NULL),
+      child_id_(-1),
+      render_view_id_(-1),
+      request_id_(-1) {
+}
+
+DownloadRequestHandle::DownloadRequestHandle(ResourceDispatcherHost* rdh,
+                                             int child_id,
+                                             int render_view_id,
+                                             int request_id)
+    : rdh_(rdh),
+      child_id_(child_id),
+      render_view_id_(render_view_id),
+      request_id_(request_id) {
+  // ResourceDispatcherHost should not be null for non-default instances
+  // of DownloadRequestHandle.
+  DCHECK(rdh);
+}
+
+TabContents* DownloadRequestHandle::GetTabContents() const {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  return tab_util::GetTabContentsByID(child_id_, render_view_id_);
+}
+
+DownloadManager* DownloadRequestHandle::GetDownloadManager() const {
+  TabContents* contents = GetTabContents();
+  if (!contents)
+    return NULL;
+
+  content::BrowserContext* browser_context = contents->browser_context();
+  if (!browser_context)
+    return NULL;
+
+  return browser_context->GetDownloadManager();
+}
+
+void DownloadRequestHandle::PauseRequest() const {
+  // The post is safe because ResourceDispatcherHost is guaranteed
+  // to outlive the IO thread.
+  if (rdh_) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        NewRunnableFunction(&ResourceDispatcherHostPauseRequest,
+                            rdh_, child_id_, request_id_, true));
+  }
+}
+
+void DownloadRequestHandle::ResumeRequest() const {
+  // The post is safe because ResourceDispatcherHost is guaranteed
+  // to outlive the IO thread.
+  if (rdh_) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        NewRunnableFunction(&ResourceDispatcherHostPauseRequest,
+                            rdh_, child_id_, request_id_, false));
+  }
+}
+
+void DownloadRequestHandle::CancelRequest() const {
+  // The post is safe because ResourceDispatcherHost is guaranteed
+  // to outlive the IO thread.
+  if (rdh_) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        NewRunnableFunction(&ResourceDispatcherHostCancelRequest,
+                            rdh_, child_id_, request_id_));
+  }
+}
+
+std::string DownloadRequestHandle::DebugString() const {
+  return base::StringPrintf("{"
+                            " child_id = %d"
+                            " render_view_id = %d"
+                            " request_id = %d"
+                            "}",
+                            child_id_,
+                            render_view_id_,
+                            request_id_);
+}
diff --git a/content/browser/download/download_request_handle.h b/content/browser/download/download_request_handle.h
new file mode 100644
index 0000000..c65ebe6
--- /dev/null
+++ b/content/browser/download/download_request_handle.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_HANDLE_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_HANDLE_H_
+#pragma once
+
+#include <string>
+
+class DownloadManager;
+class ResourceDispatcherHost;
+class TabContents;
+
+// A handle used by the download system for operations on the URLRequest
+// or objects conditional on it (e.g. TabContents).
+// This class needs to be copyable, so we can pass it across threads and not
+// worry about lifetime or const-ness.
+class DownloadRequestHandle {
+ public:
+  // Create a null DownloadRequestHandle: getters will return null, and
+  // all actions are no-ops.
+  // TODO(rdsmith): Ideally, actions would be forbidden rather than
+  // no-ops, to confirm that no non-testing code actually uses
+  // a null DownloadRequestHandle.  But for now, we need the no-op
+  // behavior for unit tests.  Long-term, this should be fixed by
+  // allowing mocking of ResourceDispatcherHost in unit tests.
+  DownloadRequestHandle();
+
+  // Note that |rdh| is required to be non-null.
+  DownloadRequestHandle(ResourceDispatcherHost* rdh,
+                        int child_id,
+                        int render_view_id,
+                        int request_id);
+
+  // These functions must be called on the UI thread.
+  TabContents* GetTabContents() const;
+  DownloadManager* GetDownloadManager() const;
+
+  // Pause or resume the matching URL request.
+  void PauseRequest() const;
+  void ResumeRequest() const;
+
+  // Cancel the request
+  void CancelRequest() const;
+
+  std::string DebugString() const;
+
+ private:
+  // The resource dispatcher host.
+  ResourceDispatcherHost* rdh_;
+
+  // The ID of the child process that started the download.
+  int child_id_;
+
+  // The ID of the render view that started the download.
+  int render_view_id_;
+
+  // The ID associated with the request used for the download.
+  int request_id_;
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_HANDLE_H_
diff --git a/content/browser/download/download_state_info.cc b/content/browser/download/download_state_info.cc
new file mode 100644
index 0000000..0631129e
--- /dev/null
+++ b/content/browser/download/download_state_info.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_state_info.h"
+
+#include "content/browser/download/download_item.h"
+
+DownloadStateInfo::DownloadStateInfo()
+    : path_uniquifier(0),
+      has_user_gesture(false),
+      prompt_user_for_save_location(false),
+      is_dangerous_file(false),
+      is_dangerous_url(false),
+      is_extension_install(false) {
+}
+
+DownloadStateInfo::DownloadStateInfo(
+    bool has_user_gesture,
+    bool prompt_user_for_save_location)
+    : path_uniquifier(0),
+      has_user_gesture(has_user_gesture),
+      prompt_user_for_save_location(prompt_user_for_save_location),
+      is_dangerous_file(false),
+      is_dangerous_url(false),
+      is_extension_install(false) {
+}
+
+DownloadStateInfo::DownloadStateInfo(
+    const FilePath& target,
+    const FilePath& forced_name,
+    bool has_user_gesture,
+    bool prompt_user_for_save_location,
+    int uniquifier,
+    bool dangerous_file,
+    bool dangerous_url,
+    bool extension_install)
+    : target_name(target),
+      path_uniquifier(uniquifier),
+      has_user_gesture(has_user_gesture),
+      prompt_user_for_save_location(prompt_user_for_save_location),
+      is_dangerous_file(dangerous_file),
+      is_dangerous_url(dangerous_url),
+      is_extension_install(extension_install),
+      force_file_name(forced_name) {
+}
+
+bool DownloadStateInfo::IsDangerous() const {
+  return is_dangerous_url || is_dangerous_file;
+}
diff --git a/content/browser/download/download_state_info.h b/content/browser/download/download_state_info.h
new file mode 100644
index 0000000..5ca4c40
--- /dev/null
+++ b/content/browser/download/download_state_info.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATE_INFO_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATE_INFO_H_
+#pragma once
+
+#include "base/file_path.h"
+
+// Contains information relating to the process of determining what to do with
+// the download.
+struct DownloadStateInfo {
+  DownloadStateInfo();
+  DownloadStateInfo(bool has_user_gesture,
+                    bool prompt_user_for_save_location);
+  DownloadStateInfo(const FilePath& target,
+                    const FilePath& forced_name,
+                    bool has_user_gesture,
+                    bool prompt_user_for_save_location,
+                    int uniquifier,
+                    bool dangerous_file,
+                    bool dangerous_url,
+                    bool extension_install);
+
+  // Indicates if the download is dangerous.
+  bool IsDangerous() const;
+
+  // The original name for a dangerous download, specified by the request.
+  FilePath target_name;
+
+  // The path where we save the download.  Typically generated.
+  FilePath suggested_path;
+
+  // A number that should be added to the suggested path to make it unique.
+  // 0 means no number should be appended.  It is eventually incorporated
+  // into the final file name.
+  int path_uniquifier;
+
+  // True if the download is the result of user action.
+  bool has_user_gesture;
+
+  // True if we should display the 'save as...' UI and prompt the user
+  // for the download location.
+  // False if the UI should be suppressed and the download performed to the
+  // default location.
+  bool prompt_user_for_save_location;
+
+  // True if this download file is potentially dangerous (ex: exe, dll, ...).
+  bool is_dangerous_file;
+
+  // If safebrowsing believes this URL leads to malware.
+  bool is_dangerous_url;
+
+  // True if this download is for extension install.
+  bool is_extension_install;
+
+  // True if this download's file name was specified initially.
+  FilePath force_file_name;
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATE_INFO_H_
diff --git a/content/browser/download/download_status_updater.cc b/content/browser/download/download_status_updater.cc
new file mode 100644
index 0000000..c2988cf0
--- /dev/null
+++ b/content/browser/download/download_status_updater.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_status_updater.h"
+
+#include "base/logging.h"
+#include "chrome/browser/download/download_util.h"
+#include "content/browser/download/download_status_updater_delegate.h"
+
+DownloadStatusUpdater::DownloadStatusUpdater() {
+}
+
+DownloadStatusUpdater::~DownloadStatusUpdater() {
+}
+
+void DownloadStatusUpdater::AddDelegate(
+    DownloadStatusUpdaterDelegate* delegate) {
+  delegates_.insert(delegate);
+  Update();
+}
+
+void DownloadStatusUpdater::RemoveDelegate(
+    DownloadStatusUpdaterDelegate* delegate) {
+  delegates_.erase(delegate);
+  Update();
+}
+
+void DownloadStatusUpdater::Update() {
+  float progress = 0;
+  bool progress_known = GetProgress(&progress);
+  download_util::UpdateAppIconDownloadProgress(
+      static_cast<int>(GetInProgressDownloadCount()),
+      progress_known,
+      progress);
+}
+
+bool DownloadStatusUpdater::GetProgress(float* progress) {
+  *progress = 0;
+
+  int64 received_bytes = 0;
+  int64 total_bytes = 0;
+  for (DelegateSet::iterator i = delegates_.begin();
+       i != delegates_.end(); ++i) {
+    if (!(*i)->IsDownloadProgressKnown())
+      return false;
+    received_bytes += (*i)->GetReceivedDownloadBytes();
+    total_bytes += (*i)->GetTotalDownloadBytes();
+  }
+
+  if (total_bytes > 0)
+    *progress = static_cast<float>(received_bytes) / total_bytes;
+  return true;
+}
+
+int64 DownloadStatusUpdater::GetInProgressDownloadCount() {
+  int64 download_count = 0;
+  for (DelegateSet::iterator i = delegates_.begin();
+       i != delegates_.end(); ++i) {
+    download_count += (*i)->GetInProgressDownloadCount();
+  }
+
+  return download_count;
+}
diff --git a/content/browser/download/download_status_updater.h b/content/browser/download/download_status_updater.h
new file mode 100644
index 0000000..0b834ec
--- /dev/null
+++ b/content/browser/download/download_status_updater.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATUS_UPDATER_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATUS_UPDATER_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/weak_ptr.h"
+
+class DownloadStatusUpdaterDelegate;
+
+// Keeps track of download progress for the entire browser.
+class DownloadStatusUpdater
+    : public base::SupportsWeakPtr<DownloadStatusUpdater> {
+ public:
+  DownloadStatusUpdater();
+  ~DownloadStatusUpdater();
+
+  void AddDelegate(DownloadStatusUpdaterDelegate* delegate);
+  void RemoveDelegate(DownloadStatusUpdaterDelegate* delegate);
+
+  // Updates the download status based on data from delegates.
+  void Update();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(DownloadStatusUpdaterTest, Basic);
+  FRIEND_TEST_ALL_PREFIXES(DownloadStatusUpdaterTest, OneDelegate);
+  FRIEND_TEST_ALL_PREFIXES(DownloadStatusUpdaterTest, MultipleDelegates);
+
+  // If the progress is known (i.e. we know the final size of all downloads),
+  // returns true and puts a percentage (in range [0-1]) in |progress|.
+  bool GetProgress(float* progress);
+
+  // Returns the number of downloads that are in progress.
+  int64 GetInProgressDownloadCount();
+
+  typedef std::set<DownloadStatusUpdaterDelegate*> DelegateSet;
+  DelegateSet delegates_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadStatusUpdater);
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATUS_UPDATER_H_
diff --git a/content/browser/download/download_status_updater_delegate.h b/content/browser/download/download_status_updater_delegate.h
new file mode 100644
index 0000000..72c2eda
--- /dev/null
+++ b/content/browser/download/download_status_updater_delegate.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATUS_UPDATER_DELEGATE_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATUS_UPDATER_DELEGATE_H_
+
+#include "base/basictypes.h"
+
+class DownloadStatusUpdaterDelegate {
+ public:
+  // Returns true if the progress is known (i.e. we know the final size
+  // of all downloads).
+  virtual bool IsDownloadProgressKnown() = 0;
+
+  // Returns the number of downloads that are in progress.
+  virtual int64 GetInProgressDownloadCount() = 0;
+
+  // Returns the amount of received data, in bytes.
+  virtual int64 GetReceivedDownloadBytes() = 0;
+
+  // Returns the final size of all downloads, in bytes.
+  virtual int64 GetTotalDownloadBytes() = 0;
+
+ protected:
+  virtual ~DownloadStatusUpdaterDelegate() {}
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_STATUS_UPDATER_DELEGATE_H_
diff --git a/content/browser/download/download_status_updater_unittest.cc b/content/browser/download/download_status_updater_unittest.cc
new file mode 100644
index 0000000..368137b
--- /dev/null
+++ b/content/browser/download/download_status_updater_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/download/download_status_updater.h"
+#include "content/browser/download/download_status_updater_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MockDelegate : public DownloadStatusUpdaterDelegate {
+ public:
+  explicit MockDelegate(DownloadStatusUpdater* updater)
+      : updater_(updater->AsWeakPtr()),
+        is_download_progress_known_(true),
+        in_progress_download_count_(0),
+        received_bytes_(0),
+        total_bytes_(0) {
+    EXPECT_TRUE(updater);
+    if (updater_)
+      updater_->AddDelegate(this);
+  }
+
+  ~MockDelegate() {
+    EXPECT_TRUE(updater_);
+    if (updater_)
+      updater_->RemoveDelegate(this);
+  }
+
+  // Overriden from DownloadStatusUpdaterDelegate:
+  virtual bool IsDownloadProgressKnown() {
+    return is_download_progress_known_;
+  }
+
+  virtual int64 GetInProgressDownloadCount() {
+    return in_progress_download_count_;
+  }
+
+  virtual int64 GetReceivedDownloadBytes() {
+    return received_bytes_;
+  }
+
+  virtual int64 GetTotalDownloadBytes() {
+    return total_bytes_;
+  }
+
+  void set_is_download_progress_known(bool progress_known) {
+    is_download_progress_known_ = progress_known;
+  }
+
+  void set_in_progress_download_count(int64 download_count) {
+    in_progress_download_count_ = download_count;
+  }
+
+  void set_received_bytes(int64 received_bytes) {
+    received_bytes_ = received_bytes;
+  }
+
+  void set_total_bytes(int64 total_bytes) {
+    total_bytes_ = total_bytes;
+  }
+
+ private:
+  base::WeakPtr<DownloadStatusUpdater> updater_;
+
+  bool is_download_progress_known_;
+  int64 in_progress_download_count_;
+  int64 received_bytes_;
+  int64 total_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockDelegate);
+};
+
+}  // namespace
+
+class DownloadStatusUpdaterTest : public testing::Test {
+ protected:
+  DownloadStatusUpdater updater_;
+};
+
+TEST_F(DownloadStatusUpdaterTest, Basic) {
+  float progress = -1;
+  EXPECT_TRUE(updater_.GetProgress(&progress));
+  EXPECT_FLOAT_EQ(0, progress);
+  EXPECT_EQ(0, updater_.GetInProgressDownloadCount());
+}
+
+TEST_F(DownloadStatusUpdaterTest, OneDelegate) {
+  MockDelegate delegate(&updater_);
+
+  {
+    float progress = -1;
+    EXPECT_TRUE(updater_.GetProgress(&progress));
+    EXPECT_FLOAT_EQ(0, progress);
+    EXPECT_EQ(0, updater_.GetInProgressDownloadCount());
+  }
+
+  delegate.set_in_progress_download_count(1);
+  delegate.set_received_bytes(21);
+  delegate.set_total_bytes(42);
+
+  {
+    float progress = -1;
+    EXPECT_TRUE(updater_.GetProgress(&progress));
+    EXPECT_FLOAT_EQ(static_cast<float>(1) / 2, progress);
+    EXPECT_EQ(1, updater_.GetInProgressDownloadCount());
+  }
+
+  delegate.set_is_download_progress_known(false);
+
+  {
+    float progress = -1;
+    EXPECT_FALSE(updater_.GetProgress(&progress));
+    EXPECT_FLOAT_EQ(0, progress);
+    EXPECT_EQ(1, updater_.GetInProgressDownloadCount());
+  }
+}
+
+TEST_F(DownloadStatusUpdaterTest, MultipleDelegates) {
+  scoped_ptr<MockDelegate> delegate1(new MockDelegate(&updater_));
+  scoped_ptr<MockDelegate> delegate2(new MockDelegate(&updater_));
+
+  {
+    float progress = -1;
+    EXPECT_TRUE(updater_.GetProgress(&progress));
+    EXPECT_FLOAT_EQ(0, progress);
+    EXPECT_EQ(0, updater_.GetInProgressDownloadCount());
+  }
+
+  delegate1->set_in_progress_download_count(1);
+  delegate1->set_received_bytes(14);
+  delegate1->set_total_bytes(21);
+
+  delegate2->set_in_progress_download_count(2);
+  delegate2->set_received_bytes(7);
+  delegate2->set_total_bytes(21);
+
+  {
+    float progress = -1;
+    EXPECT_TRUE(updater_.GetProgress(&progress));
+    EXPECT_FLOAT_EQ(static_cast<float>(1) / 2, progress);
+    EXPECT_EQ(3, updater_.GetInProgressDownloadCount());
+  }
+
+  delegate1->set_is_download_progress_known(false);
+
+  {
+    float progress = -1;
+    EXPECT_FALSE(updater_.GetProgress(&progress));
+    EXPECT_FLOAT_EQ(0, progress);
+    EXPECT_EQ(3, updater_.GetInProgressDownloadCount());
+  }
+
+  delegate1.reset();
+
+  {
+    float progress = -1;
+    EXPECT_TRUE(updater_.GetProgress(&progress));
+    EXPECT_FLOAT_EQ(static_cast<float>(1) / 3, progress);
+    EXPECT_EQ(2, updater_.GetInProgressDownloadCount());
+  }
+}
diff --git a/content/browser/download/download_types.cc b/content/browser/download/download_types.cc
new file mode 100644
index 0000000..b54d7f20
--- /dev/null
+++ b/content/browser/download/download_types.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_types.h"
+
+DownloadBuffer::DownloadBuffer() {
+}
+
+DownloadBuffer::~DownloadBuffer() {
+}
+
+DownloadSaveInfo::DownloadSaveInfo() {
+}
+
+DownloadSaveInfo::DownloadSaveInfo(const DownloadSaveInfo& info)
+    : file_path(info.file_path),
+      file_stream(info.file_stream),
+      suggested_name(info.suggested_name) {
+}
+
+DownloadSaveInfo::~DownloadSaveInfo() {
+}
+
+DownloadSaveInfo& DownloadSaveInfo::operator=(const DownloadSaveInfo& info) {
+  file_path = info.file_path;
+  file_stream = info.file_stream;
+  suggested_name = info.suggested_name;
+  return *this;
+}
diff --git a/content/browser/download/download_types.h b/content/browser/download/download_types.h
new file mode 100644
index 0000000..b4f4a366
--- /dev/null
+++ b/content/browser/download/download_types.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_TYPES_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_TYPES_H_
+#pragma once
+
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/memory/linked_ptr.h"
+#include "base/synchronization/lock.h"
+#include "net/base/file_stream.h"
+
+namespace net {
+class IOBuffer;
+}
+
+// DownloadBuffer is created and populated on the IO thread, and passed to the
+// file thread for writing. In order to avoid flooding the file thread with too
+// many small write messages, each write is appended to the DownloadBuffer while
+// waiting for the task to run on the file thread. Access to the write buffers
+// is synchronized via the lock. Each entry in 'contents' represents one data
+// buffer and its size in bytes.
+struct DownloadBuffer {
+  DownloadBuffer();
+  ~DownloadBuffer();
+
+  base::Lock lock;
+  typedef std::pair<net::IOBuffer*, int> Contents;
+  std::vector<Contents> contents;
+};
+
+// Holds the information about how to save a download file.
+struct DownloadSaveInfo {
+  DownloadSaveInfo();
+  DownloadSaveInfo(const DownloadSaveInfo& info);
+  ~DownloadSaveInfo();
+  DownloadSaveInfo& operator=(const DownloadSaveInfo& info);
+
+  FilePath file_path;
+  linked_ptr<net::FileStream> file_stream;
+  string16 suggested_name;
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_TYPES_H_
diff --git a/content/browser/download/mock_download_manager.h b/content/browser/download/mock_download_manager.h
new file mode 100644
index 0000000..48689b5
--- /dev/null
+++ b/content/browser/download/mock_download_manager.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_MOCK_DOWNLOAD_MANAGER_H_
+#define CONTENT_BROWSER_DOWNLOAD_MOCK_DOWNLOAD_MANAGER_H_
+#pragma once
+
+#include "content/browser/download/download_manager.h"
+
+class DownloadStatusUpdater;
+class DownloadItem;
+
+class MockDownloadManager : public DownloadManager {
+ public:
+  explicit MockDownloadManager(DownloadManagerDelegate* delegate,
+                               DownloadStatusUpdater* updater)
+      : DownloadManager(delegate, updater) {
+  }
+
+  // Override some functions.
+  virtual void UpdateHistoryForDownload(DownloadItem*) { }
+};
+
+#endif  // CONTENT_BROWSER_DOWNLOAD_MOCK_DOWNLOAD_MANAGER_H_
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index 82b4153..e831b40 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -19,14 +19,14 @@
 #include "base/threading/thread.h"
 #include "base/utf_string_conversions.h"
 #include "chrome/browser/download/download_history.h"
-#include "chrome/browser/download/download_item.h"
 #include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/download/download_manager.h"
 #include "chrome/browser/download/download_manager_delegate.h"
 #include "chrome/browser/download/download_util.h"
 #include "content/browser/browser_context.h"
 #include "content/browser/browser_thread.h"
 #include "content/browser/content_browser_client.h"
+#include "content/browser/download/download_item.h"
+#include "content/browser/download/download_manager.h"
 #include "content/browser/download/save_file.h"
 #include "content/browser/download/save_file_manager.h"
 #include "content/browser/download/save_item.h"
diff --git a/content/browser/download/save_package.h b/content/browser/download/save_package.h
index 76e4b62..824a336 100644
--- a/content/browser/download/save_package.h
+++ b/content/browser/download/save_package.h
@@ -17,7 +17,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task.h"
-#include "chrome/browser/download/download_manager.h"
+#include "content/browser/download/download_manager.h"
 #include "content/browser/tab_contents/tab_contents_observer.h"
 #include "googleurl/src/gurl.h"