Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6200)

Unified Diff: chrome/browser/download_file.cc

Issue 2826: Move the download code to new directories: (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/download_file.h ('k') | chrome/browser/download_item_model.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/download_file.cc
===================================================================
--- chrome/browser/download_file.cc (revision 2162)
+++ chrome/browser/download_file.cc (working copy)
@@ -1,580 +0,0 @@
-// Copyright (c) 2006-2008 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 <Windows.h>
-#include <objbase.h>
-
-#include "chrome/browser/download_file.h"
-
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "base/task.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/download_manager.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/resource_dispatcher_host.h"
-#include "chrome/browser/tab_contents.h"
-#include "chrome/browser/tab_util.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/stl_util-inl.h"
-#include "chrome/common/win_util.h"
-#include "chrome/common/win_safe_util.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/net_util.h"
-#include "net/url_request/url_request_context.h"
-
-// Throttle updates to the UI thread so that a fast moving download doesn't
-// cause it to become unresponsive (ins milliseconds).
-static const int kUpdatePeriodMs = 500;
-
-// Timer task for posting UI updates. This task is created and maintained by
-// the DownloadFileManager long as there is an in progress download. The task
-// is cancelled when all active downloads have completed, or in the destructor
-// of the DownloadFileManager.
-class DownloadFileUpdateTask : public Task {
- public:
- explicit DownloadFileUpdateTask(DownloadFileManager* manager)
- : manager_(manager) {}
- virtual void Run() {
- manager_->UpdateInProgressDownloads();
- }
-
- private:
- DownloadFileManager* manager_;
-
- DISALLOW_EVIL_CONSTRUCTORS(DownloadFileUpdateTask);
-};
-
-// DownloadFile implementation -------------------------------------------------
-
-DownloadFile::DownloadFile(const DownloadCreateInfo* info)
- : file_(NULL),
- id_(info->download_id),
- render_process_id_(info->render_process_id),
- render_view_id_(info->render_view_id),
- request_id_(info->request_id),
- bytes_so_far_(0),
- path_renamed_(false),
- in_progress_(true) {
-}
-
-DownloadFile::~DownloadFile() {
- Close();
-}
-
-bool DownloadFile::Initialize() {
- if (file_util::CreateTemporaryFileName(&full_path_))
- return Open(L"wb");
- return false;
-}
-
-// FIXME bug 595247: handle errors on file writes.
-bool DownloadFile::AppendDataToFile(const char* data, int data_len) {
- if (file_) {
- fwrite(data, 1, data_len, file_);
- bytes_so_far_ += data_len;
- return true;
- }
- return false;
-}
-
-void DownloadFile::Cancel() {
- Close();
- DeleteFile(full_path_.c_str());
-}
-
-// The UI has provided us with our finalized name.
-bool DownloadFile::Rename(const std::wstring& new_path) {
- Close();
-
- // We cannot rename because rename will keep the same security descriptor
- // on the destination file. We want to recreate the security descriptor
- // with the security that makes sense in the new path.
- if (!file_util::RenameFileAndResetSecurityDescriptor(full_path_.c_str(),
- new_path.c_str())) {
- return false;
- }
-
- DeleteFile(full_path_.c_str());
-
- full_path_ = new_path;
- path_renamed_ = true;
-
- // We don't need to re-open the file if we're done (finished or canceled).
- if (!in_progress_)
- return true;
-
- if (!Open(L"a+b"))
- return false;
- return true;
-}
-
-void DownloadFile::Close() {
- if (file_) {
- fclose(file_);
- file_ = NULL;
- }
-}
-
-bool DownloadFile::Open(const wchar_t* open_mode) {
- DCHECK(!full_path_.empty());
- if (_wfopen_s(&file_, full_path_.c_str(), open_mode)) {
- file_ = NULL;
- return false;
- }
- // Sets the Zone to tell Windows that this file comes from the internet.
- // We ignore the return value because a failure is not fatal.
- win_util::SetInternetZoneIdentifier(full_path_);
- return true;
-}
-
-// DownloadFileManager implementation ------------------------------------------
-
-DownloadFileManager::DownloadFileManager(MessageLoop* ui_loop,
- ResourceDispatcherHost* rdh)
- : next_id_(0),
- ui_loop_(ui_loop),
- resource_dispatcher_host_(rdh) {
-}
-
-DownloadFileManager::~DownloadFileManager() {
- // Check for clean shutdown.
- DCHECK(downloads_.empty());
- ui_progress_.clear();
-}
-
-void DownloadFileManager::Initialize() {
- io_loop_ = g_browser_process->io_thread()->message_loop();
- file_loop_ = g_browser_process->file_thread()->message_loop();
-}
-
-// Called during the browser shutdown process to clean up any state (open files,
-// timers) that live on the download_thread_.
-void DownloadFileManager::Shutdown() {
- DCHECK(MessageLoop::current() == ui_loop_);
- StopUpdateTimer();
- file_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &DownloadFileManager::OnShutdown));
-}
-
-// Cease download thread operations.
-void DownloadFileManager::OnShutdown() {
- DCHECK(MessageLoop::current() == file_loop_);
- // Delete any partial downloads during shutdown.
- for (DownloadFileMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- DownloadFile* download = it->second;
- if (download->in_progress())
- download->Cancel();
- delete download;
- }
- downloads_.clear();
-}
-
-// Lookup one in-progress download.
-DownloadFile* DownloadFileManager::LookupDownload(int id) {
- DownloadFileMap::iterator it = downloads_.find(id);
- return it == downloads_.end() ? NULL : it->second;
-}
-
-// The UI progress is updated on the file thread and removed on the UI thread.
-void DownloadFileManager::RemoveDownloadFromUIProgress(int id) {
- DCHECK(MessageLoop::current() == ui_loop_);
- AutoLock lock(progress_lock_);
- if (ui_progress_.find(id) != ui_progress_.end())
- ui_progress_.erase(id);
-}
-
-// Throttle updates to the UI thread by only posting update notifications at a
-// regularly controlled interval.
-void DownloadFileManager::StartUpdateTimer() {
- DCHECK(MessageLoop::current() == ui_loop_);
- if (!update_timer_.IsRunning()) {
- update_timer_.Start(TimeDelta::FromMilliseconds(kUpdatePeriodMs), this,
- &DownloadFileManager::UpdateInProgressDownloads);
- }
-}
-
-void DownloadFileManager::StopUpdateTimer() {
- DCHECK(MessageLoop::current() == ui_loop_);
- update_timer_.Stop();
-}
-
-// Called on the IO thread once the ResourceDispatcherHost has decided that a
-// request is a download.
-int DownloadFileManager::GetNextId() {
- DCHECK(MessageLoop::current() == io_loop_);
- return next_id_++;
-}
-
-// Notifications sent from the IO thread and run on the download thread:
-
-// The IO thread created 'info', but the download thread (this method) uses it
-// to create a DownloadFile, then passes 'info' to the UI thread where it is
-// finally consumed and deleted.
-void DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
- DCHECK(MessageLoop::current() == file_loop_);
- DCHECK(info);
-
- DownloadFile* download = new DownloadFile(info);
- if (!download->Initialize()) {
- // Couldn't open, cancel the operation. The UI thread does not yet know
- // about this download so we have to clean up 'info'. We need to get back
- // to the IO thread to cancel the network request and CancelDownloadRequest
- // on the UI thread is the safe way to do that.
- ui_loop_->PostTask(FROM_HERE,
- NewRunnableFunction(&DownloadManager::CancelDownloadRequest,
- info->render_process_id,
- info->request_id));
- delete info;
- delete download;
- return;
- }
-
- DCHECK(LookupDownload(info->download_id) == NULL);
- downloads_[info->download_id] = download;
- info->path = download->full_path();
- {
- AutoLock lock(progress_lock_);
- ui_progress_[info->download_id] = info->received_bytes;
- }
-
- ui_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &DownloadFileManager::OnStartDownload,
- info));
-}
-
-// 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(MessageLoop::current() == file_loop_);
- std::vector<DownloadBuffer::Contents> contents;
- {
- AutoLock auto_lock(buffer->lock);
- contents.swap(buffer->contents);
- }
-
- DownloadFile* download = LookupDownload(id);
- for (size_t i = 0; i < contents.size(); ++i) {
- char* data = contents[i].first;
- const int data_len = contents[i].second;
- if (download)
- download->AppendDataToFile(data, data_len);
- delete [] data;
- }
-
- if (download) {
- AutoLock lock(progress_lock_);
- ui_progress_[download->id()] = download->bytes_so_far();
- }
-}
-
-void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) {
- DCHECK(MessageLoop::current() == file_loop_);
- delete buffer;
- DownloadFileMap::iterator it = downloads_.find(id);
- if (it != downloads_.end()) {
- DownloadFile* download = it->second;
- download->set_in_progress(false);
-
- ui_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &DownloadFileManager::OnDownloadFinished,
- id,
- download->bytes_so_far()));
-
- // We need to keep the download around until the UI thread has finalized
- // the name.
- if (download->path_renamed()) {
- downloads_.erase(it);
- delete download;
- }
- }
-
- if (downloads_.empty())
- ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- this, &DownloadFileManager::StopUpdateTimer));
-}
-
-// 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) {
- DCHECK(MessageLoop::current() == file_loop_);
- DownloadFileMap::iterator it = downloads_.find(id);
- if (it != downloads_.end()) {
- DownloadFile* download = it->second;
- download->set_in_progress(false);
-
- download->Cancel();
-
- ui_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &DownloadFileManager::RemoveDownloadFromUIProgress,
- download->id()));
-
- if (download->path_renamed()) {
- downloads_.erase(it);
- delete download;
- }
- }
-
- if (downloads_.empty())
- ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- this, &DownloadFileManager::StopUpdateTimer));
-}
-
-// Our periodic timer has fired so send the UI thread updates on all in progress
-// downloads.
-void DownloadFileManager::UpdateInProgressDownloads() {
- DCHECK(MessageLoop::current() == ui_loop_);
- AutoLock lock(progress_lock_);
- ProgressMap::iterator it = ui_progress_.begin();
- for (; it != ui_progress_.end(); ++it) {
- const int id = it->first;
- DownloadManager* manager = LookupManager(id);
- if (manager)
- manager->UpdateDownload(id, it->second);
- }
-}
-
-// Notifications sent from the download thread and run on the UI thread.
-
-// Lookup the DownloadManager for this WebContents' profile and inform it of
-// a new download.
-// TODO(paulg): When implementing download restart via the Downloads tab,
-// there will be no 'render_process_id' or 'render_view_id'.
-void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) {
- DCHECK(MessageLoop::current() == ui_loop_);
- DownloadManager* manager =
- DownloadManagerFromRenderIds(info->render_process_id,
- info->render_view_id);
- if (!manager) {
- DownloadManager::CancelDownloadRequest(info->render_process_id,
- info->request_id);
- delete info;
- return;
- }
-
- StartUpdateTimer();
-
- // Add the download manager to our request maps for future updates. We want to
- // be able to cancel all in progress downloads when a DownloadManager is
- // deleted, such as when a profile is closed. We also want to be able to look
- // up the DownloadManager associated with a given request without having to
- // rely on using tab information, since a tab may be closed while a download
- // initiated from that tab is still in progress.
- DownloadRequests& downloads = requests_[manager];
- downloads.insert(info->download_id);
-
- // TODO(paulg): The manager will exist when restarts are implemented.
- DownloadManagerMap::iterator dit = managers_.find(info->download_id);
- if (dit == managers_.end())
- managers_[info->download_id] = manager;
- else
- NOTREACHED();
-
- // StartDownload will clean up |info|.
- manager->StartDownload(info);
-}
-
-// Update the Download Manager with the finish state, and remove the request
-// tracking entries.
-void DownloadFileManager::OnDownloadFinished(int id,
- int64 bytes_so_far) {
- DCHECK(MessageLoop::current() == ui_loop_);
- DownloadManager* manager = LookupManager(id);
- if (manager)
- manager->DownloadFinished(id, bytes_so_far);
- RemoveDownload(id, manager);
- RemoveDownloadFromUIProgress(id);
-}
-
-void DownloadFileManager::DownloadUrl(const GURL& url,
- const GURL& referrer,
- int render_process_host_id,
- int render_view_id,
- URLRequestContext* request_context) {
- DCHECK(MessageLoop::current() == ui_loop_);
- base::Thread* thread = g_browser_process->io_thread();
- if (thread) {
- thread->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &DownloadFileManager::OnDownloadUrl,
- url,
- referrer,
- render_process_host_id,
- render_view_id,
- request_context));
- }
-}
-
-// Relate a download ID to its owning DownloadManager.
-DownloadManager* DownloadFileManager::LookupManager(int download_id) {
- DCHECK(MessageLoop::current() == ui_loop_);
- DownloadManagerMap::iterator it = managers_.find(download_id);
- if (it != managers_.end())
- return it->second;
- return NULL;
-}
-
-// Utility function for look up table maintenance, called on the UI thread.
-// A manager may have multiple downloads in progress, so we just look up the
-// one download (id) and remove it from the set, and remove the set if it
-// becomes empty.
-void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) {
- DCHECK(MessageLoop::current() == ui_loop_);
- if (manager) {
- RequestMap::iterator it = requests_.find(manager);
- if (it != requests_.end()) {
- DownloadRequests& downloads = it->second;
- DownloadRequests::iterator rit = downloads.find(id);
- if (rit != downloads.end())
- downloads.erase(rit);
- if (downloads.empty())
- requests_.erase(it);
- }
- }
-
- // A download can only have one manager, so remove it if it exists.
- DownloadManagerMap::iterator dit = managers_.find(id);
- if (dit != managers_.end())
- managers_.erase(dit);
-}
-
-// Utility function for converting request IDs to a TabContents. Must be called
-// only on the UI thread since Profile operations may create UI objects, such as
-// the first call to profile->GetDownloadManager().
-// static
-DownloadManager* DownloadFileManager::DownloadManagerFromRenderIds(
- int render_process_id, int render_view_id) {
- TabContents* contents = tab_util::GetTabContentsByID(render_process_id,
- render_view_id);
- if (contents && contents->type() == TAB_CONTENTS_WEB) {
- Profile* profile = contents->profile();
- if (profile)
- return profile->GetDownloadManager();
- }
-
- return NULL;
-}
-
-// Called by DownloadManagers in their destructor, and only on the UI thread.
-void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) {
- DCHECK(MessageLoop::current() == ui_loop_);
- DCHECK(manager);
- RequestMap::iterator it = requests_.find(manager);
- if (it == requests_.end())
- return;
-
- const DownloadRequests& requests = it->second;
- DownloadRequests::const_iterator i = requests.begin();
- for (; i != requests.end(); ++i) {
- DownloadManagerMap::iterator dit = managers_.find(*i);
- if (dit != managers_.end()) {
- DCHECK(dit->second == manager);
- managers_.erase(dit);
- }
- }
-
- requests_.erase(it);
-}
-
-
-// Notifications from the UI thread and run on the IO thread
-
-// Initiate a request for URL to be downloaded.
-void DownloadFileManager::OnDownloadUrl(const GURL& url,
- const GURL& referrer,
- int render_process_host_id,
- int render_view_id,
- URLRequestContext* request_context) {
- DCHECK(MessageLoop::current() == io_loop_);
- resource_dispatcher_host_->BeginDownload(url,
- referrer,
- render_process_host_id,
- render_view_id,
- request_context);
-}
-
-// Actions from the UI thread and run on the download thread
-
-// Open a download, or show it in a Windows Explorer window. We run on this
-// thread to avoid blocking the UI with (potentially) slow Shell operations.
-// TODO(paulg): File 'stat' operations.
-void DownloadFileManager::OnShowDownloadInShell(const std::wstring full_path) {
- DCHECK(MessageLoop::current() == file_loop_);
- win_util::ShowItemInFolder(full_path);
-}
-
-// Launches the selected download using ShellExecute 'open' verb. If there is
-// a valid parent window, the 'safer' version will be used which can
-// display a modal dialog asking for user consent on dangerous files.
-void DownloadFileManager::OnOpenDownloadInShell(const std::wstring full_path,
- const std::wstring& url,
- HWND parent_window) {
- DCHECK(MessageLoop::current() == file_loop_);
- if (NULL != parent_window) {
- win_util::SaferOpenItemViaShell(parent_window, L"", full_path, url, true);
- } else {
- win_util::OpenItemViaShell(full_path, true);
- }
-}
-
-// The DownloadManager in the UI thread has provided a final name for the
-// download specified by 'id'. Rename the in progress download, and remove it
-// from our table if it has been completed or cancelled already.
-void DownloadFileManager::OnFinalDownloadName(int id,
- const std::wstring& full_path) {
- DCHECK(MessageLoop::current() == file_loop_);
- DownloadFileMap::iterator it = downloads_.find(id);
- if (it == downloads_.end())
- return;
-
- std::wstring download_dir = file_util::GetDirectoryFromPath(full_path);
- if (!file_util::PathExists(download_dir))
- file_util::CreateDirectory(download_dir);
-
- DownloadFile* download = it->second;
- if (!download->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.
- DownloadManagerMap::iterator dmit = managers_.find(download->id());
- if (dmit != managers_.end()) {
- DownloadManager* dlm = dmit->second;
- ui_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(dlm,
- &DownloadManager::DownloadCancelled,
- id));
- } else {
- ui_loop_->PostTask(FROM_HERE,
- NewRunnableFunction(&DownloadManager::CancelDownloadRequest,
- download->render_process_id(),
- download->request_id()));
- }
- }
-
- // If the download has completed before we got this final name, we remove it
- // from our in progress map.
- if (!download->in_progress()) {
- downloads_.erase(it);
- delete download;
- }
-
- if (downloads_.empty())
- ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- this, &DownloadFileManager::StopUpdateTimer));
-}
-
-void DownloadFileManager::CreateDirectory(const std::wstring& directory) {
- if (!file_util::PathExists(directory))
- file_util::CreateDirectory(directory);
-}
« no previous file with comments | « chrome/browser/download_file.h ('k') | chrome/browser/download_item_model.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698