diff options
28 files changed, 651 insertions, 481 deletions
diff --git a/app/app_base.gypi b/app/app_base.gypi index daa2f52..fdc8854 100644 --- a/app/app_base.gypi +++ b/app/app_base.gypi @@ -106,6 +106,7 @@ 'drag_drop_types_gtk.cc', 'drag_drop_types_win.cc', 'drag_drop_types.h', + 'file_download_interface.h', 'gfx/blit.cc', 'gfx/blit.h', 'gfx/canvas.cc', diff --git a/app/download_file_interface.h b/app/download_file_interface.h new file mode 100644 index 0000000..13d2dcf --- /dev/null +++ b/app/download_file_interface.h @@ -0,0 +1,46 @@ +// Copyright (c) 2009 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 APP_DOWNLOAD_FILE_INTERFACE_H_ +#define APP_DOWNLOAD_FILE_INTERFACE_H_ + +#include "build/build_config.h" + +#include "base/basictypes.h" +#include "base/ref_counted.h" + +#if defined(OS_WIN) +#include <objidl.h> +#endif + +class FilePath; + +// Defines the interface to observe the status of file download. +class DownloadFileObserver + : public base::RefCountedThreadSafe<DownloadFileObserver> { + public: + virtual void OnDownloadCompleted(const FilePath& file_path) = 0; + virtual void OnDownloadAborted() = 0; + + protected: + friend class base::RefCountedThreadSafe<DownloadFileObserver>; + virtual ~DownloadFileObserver() {} +}; + +// Defines the interface to control how a file is downloaded. +class DownloadFileProvider + : public base::RefCountedThreadSafe<DownloadFileProvider> { + public: + virtual bool Start(DownloadFileObserver* observer) = 0; + virtual void Stop() = 0; +#if defined(OS_WIN) + virtual IStream* GetStream() = 0; +#endif + + protected: + friend class base::RefCountedThreadSafe<DownloadFileProvider>; + virtual ~DownloadFileProvider() {} +}; + +#endif // APP_DOWNLOAD_FILE_INTERFACE_H_ diff --git a/app/os_exchange_data.cc b/app/os_exchange_data.cc index dc57cd1..8081f37 100644 --- a/app/os_exchange_data.cc +++ b/app/os_exchange_data.cc @@ -129,7 +129,7 @@ bool OSExchangeData::GetHtml(std::wstring* html, GURL* base_url) const { return provider_->GetHtml(html, base_url); } -void OSExchangeData::SetDownloadFileInfo(DownloadFileInfo* download) { +void OSExchangeData::SetDownloadFileInfo(const DownloadFileInfo& download) { return provider_->SetDownloadFileInfo(download); } #endif diff --git a/app/os_exchange_data.h b/app/os_exchange_data.h index b38e655..316db88 100644 --- a/app/os_exchange_data.h +++ b/app/os_exchange_data.h @@ -17,9 +17,9 @@ #include <gtk/gtk.h> #endif +#include "app/download_file_interface.h" #include "base/basictypes.h" #include "base/file_path.h" -#include "base/ref_counted.h" #include "base/scoped_ptr.h" class GURL; @@ -61,45 +61,13 @@ class OSExchangeData { #endif }; - struct DownloadFileInfo; - - // Defines the interface to observe the status of file download. - class DownloadFileObserver : public base::RefCounted<DownloadFileObserver> { - public: - // The caller is responsible to free the DownloadFileInfo objects passed - // in the vector parameter. - virtual void OnDataReady( - int format, - const std::vector<DownloadFileInfo*>& downloads) = 0; - - protected: - friend class base::RefCounted<DownloadFileObserver>; - virtual ~DownloadFileObserver() {} - }; - - // Defines the interface to control how a file is downloaded. - class DownloadFileProvider : - public base::RefCountedThreadSafe<DownloadFileProvider> { - public: - virtual bool Start(DownloadFileObserver* observer, int format) = 0; - virtual void Stop() = 0; - - protected: - friend class base::RefCountedThreadSafe<DownloadFileProvider>; - virtual ~DownloadFileProvider() {} - }; - // Encapsulates the info about a file to be downloaded. struct DownloadFileInfo { FilePath filename; - uint64 size; scoped_refptr<DownloadFileProvider> downloader; - DownloadFileInfo(const FilePath& filename, - uint64 size, - DownloadFileProvider* downloader) + DownloadFileInfo(const FilePath& filename, DownloadFileProvider* downloader) : filename(filename), - size(size), downloader(downloader) {} }; @@ -135,7 +103,7 @@ class OSExchangeData { virtual bool GetHtml(std::wstring* html, GURL* base_url) const = 0; virtual bool HasFileContents() const = 0; virtual bool HasHtml() const = 0; - virtual void SetDownloadFileInfo(DownloadFileInfo* download) = 0; + virtual void SetDownloadFileInfo(const DownloadFileInfo& download) = 0; #endif }; @@ -211,7 +179,7 @@ class OSExchangeData { bool GetHtml(std::wstring* html, GURL* base_url) const; // Adds a download file with full path (CF_HDROP). - void SetDownloadFileInfo(DownloadFileInfo* download); + void SetDownloadFileInfo(const DownloadFileInfo& download); #endif private: diff --git a/app/os_exchange_data_provider_win.cc b/app/os_exchange_data_provider_win.cc index dc28597..8f953d1 100644 --- a/app/os_exchange_data_provider_win.cc +++ b/app/os_exchange_data_provider_win.cc @@ -455,17 +455,17 @@ bool OSExchangeDataProviderWin::HasCustomFormat(CLIPFORMAT format) const { } void OSExchangeDataProviderWin::SetDownloadFileInfo( - OSExchangeData::DownloadFileInfo* download) { + const OSExchangeData::DownloadFileInfo& download) { // If the filename is not provided, set stoarge to NULL to indicate that // the delay rendering will be used. STGMEDIUM* storage = NULL; - if (!download->filename.empty()) - storage = GetStorageForFileName(download->filename.value()); + if (!download.filename.empty()) + storage = GetStorageForFileName(download.filename.value()); // Add CF_HDROP. DataObjectImpl::StoredDataInfo* info = new DataObjectImpl::StoredDataInfo( ClipboardUtil::GetCFHDropFormat()->cfFormat, storage); - info->downloads.push_back(download); + info->downloader = download.downloader; data_->contents_.push_back(info); } @@ -560,35 +560,18 @@ DataObjectImpl::~DataObjectImpl() { void DataObjectImpl::StopDownloads() { for (StoredData::iterator iter = contents_.begin(); iter != contents_.end(); ++iter) { - for (size_t i = 0; i < (*iter)->downloads.size(); ++i) { - if ((*iter)->downloads[i]->downloader) { - (*iter)->downloads[i]->downloader->Stop(); - (*iter)->downloads[i]->downloader = 0; - } - delete (*iter)->downloads[i]; + if ((*iter)->downloader.get()) { + (*iter)->downloader->Stop(); + (*iter)->downloader = 0; } - (*iter)->downloads.clear(); } } -void DataObjectImpl::OnDataReady( - int format, - const std::vector<OSExchangeData::DownloadFileInfo*>& downloads) { - // Find and update the data corresponding to the format. - CLIPFORMAT clip_format = static_cast<CLIPFORMAT>(format); - DCHECK(clip_format == ClipboardUtil::GetCFHDropFormat()->cfFormat); +void DataObjectImpl::OnDownloadCompleted(const FilePath& file_path) { + CLIPFORMAT hdrop_format = ClipboardUtil::GetCFHDropFormat()->cfFormat; DataObjectImpl::StoredData::iterator iter = contents_.begin(); for (; iter != contents_.end(); ++iter) { - if ((*iter)->format_etc.cfFormat == clip_format) { - // Update the downloads. - DCHECK(downloads.size() == (*iter)->downloads.size()); - for (size_t i = 0; i < (*iter)->downloads.size(); ++i) { - OSExchangeData::DownloadFileInfo* old_download = (*iter)->downloads[i]; - (*iter)->downloads[i] = downloads[i]; - (*iter)->downloads[i]->downloader = old_download->downloader; - delete old_download; - } - + if ((*iter)->format_etc.cfFormat == hdrop_format) { // Release the old storage. if ((*iter)->owns_medium) { ReleaseStgMedium((*iter)->medium); @@ -597,7 +580,7 @@ void DataObjectImpl::OnDataReady( // Update the storage. (*iter)->owns_medium = true; - (*iter)->medium = GetStorageForFileName(downloads[0]->filename.value()); + (*iter)->medium = GetStorageForFileName(file_path.value()); break; } @@ -605,6 +588,9 @@ void DataObjectImpl::OnDataReady( DCHECK(iter != contents_.end()); } +void DataObjectImpl::OnDownloadAborted() { +} + HRESULT DataObjectImpl::GetData(FORMATETC* format_etc, STGMEDIUM* medium) { if (is_aborting_) return DV_E_FORMATETC; @@ -629,7 +615,12 @@ HRESULT DataObjectImpl::GetData(FORMATETC* format_etc, STGMEDIUM* medium) { if (is_left_button_down) return DV_E_FORMATETC; - wait_for_data = true; + // In async mode, we do not want to start waiting for the data before + // the async operation is started. This is because we want to postpone + // until Shell kicks off a background thread to do the work so that + // we do not block the UI thread. + if (!in_async_mode_ || async_operation_started_) + wait_for_data = true; } else { // If the left button is up and the target has not requested the data // yet, it probably means that the target does not support delay- @@ -648,18 +639,11 @@ HRESULT DataObjectImpl::GetData(FORMATETC* format_etc, STGMEDIUM* medium) { if (observer_) observer_->OnWaitForData(); - // Now we can start the downloads. Each download will wait till the - // necessary data is ready and then return the control. - for (size_t i = 0; i < (*iter)->downloads.size(); ++i) { - if ((*iter)->downloads[i]->downloader) { - if (!(*iter)->downloads[i]->downloader->Start( - this, format_etc->cfFormat)) { - // If any of the download fails to start, abort the whole - // process. - is_aborting_ = true; - StopDownloads(); - return DV_E_FORMATETC; - } + // Now we can start the download. + if ((*iter)->downloader.get()) { + if (!(*iter)->downloader->Start(this)) { + is_aborting_ = true; + return DV_E_FORMATETC; } } @@ -788,12 +772,12 @@ HRESULT DataObjectImpl::QueryInterface(const IID& iid, void** object) { } ULONG DataObjectImpl::AddRef() { - base::RefCounted<OSExchangeData::DownloadFileObserver>::AddRef(); + base::RefCountedThreadSafe<DownloadFileObserver>::AddRef(); return 0; } ULONG DataObjectImpl::Release() { - base::RefCounted<OSExchangeData::DownloadFileObserver>::Release(); + base::RefCountedThreadSafe<DownloadFileObserver>::Release(); return 0; } @@ -918,6 +902,7 @@ static STGMEDIUM* GetStorageForFileDescriptor( return storage; } + /////////////////////////////////////////////////////////////////////////////// // OSExchangeData, public: diff --git a/app/os_exchange_data_provider_win.h b/app/os_exchange_data_provider_win.h index 4bd0d80..6ea014b 100644 --- a/app/os_exchange_data_provider_win.h +++ b/app/os_exchange_data_provider_win.h @@ -12,7 +12,7 @@ #include "app/os_exchange_data.h" #include "base/scoped_comptr_win.h" -class DataObjectImpl : public OSExchangeData::DownloadFileObserver, +class DataObjectImpl : public DownloadFileObserver, public IDataObject, public IAsyncOperation { public: @@ -30,9 +30,8 @@ class DataObjectImpl : public OSExchangeData::DownloadFileObserver, void set_observer(Observer* observer) { observer_ = observer; } // DownloadFileObserver implementation: - virtual void OnDataReady( - int format, - const std::vector<OSExchangeData::DownloadFileInfo*>& downloads); + virtual void OnDownloadCompleted(const FilePath& file_path); + virtual void OnDownloadAborted(); // IDataObject implementation: HRESULT __stdcall GetData(FORMATETC* format_etc, STGMEDIUM* medium); @@ -77,7 +76,7 @@ class DataObjectImpl : public OSExchangeData::DownloadFileObserver, STGMEDIUM* medium; bool owns_medium; bool in_delay_rendering; - std::vector<OSExchangeData::DownloadFileInfo*> downloads; + scoped_refptr<DownloadFileProvider> downloader; StoredDataInfo(CLIPFORMAT cf, STGMEDIUM* medium) : medium(medium), @@ -102,11 +101,8 @@ class DataObjectImpl : public OSExchangeData::DownloadFileObserver, ReleaseStgMedium(medium); delete medium; } - for (size_t i = 0; i < downloads.size(); ++i) { - if (downloads[i]->downloader) - downloads[i]->downloader->Stop(); - } - downloads.clear(); + if (downloader.get()) + downloader->Stop(); } }; @@ -167,7 +163,7 @@ class OSExchangeDataProviderWin : public OSExchangeData::Provider { virtual bool HasHtml() const; virtual bool HasCustomFormat(OSExchangeData::CustomFormat format) const; virtual void SetDownloadFileInfo( - OSExchangeData::DownloadFileInfo* download_info); + const OSExchangeData::DownloadFileInfo& download_info); private: scoped_refptr<DataObjectImpl> data_; diff --git a/chrome/browser/download/download_file.cc b/chrome/browser/download/download_file.cc index 25a0900..b152d18 100644 --- a/chrome/browser/download/download_file.cc +++ b/chrome/browser/download/download_file.cc @@ -57,7 +57,7 @@ class DownloadFileUpdateTask : public Task { // DownloadFile implementation ------------------------------------------------- DownloadFile::DownloadFile(const DownloadCreateInfo* info) - : file_(NULL), + : file_stream_(info->save_info.file_stream), source_url_(info->url), referrer_url_(info->referrer_url), id_(info->download_id), @@ -65,9 +65,11 @@ DownloadFile::DownloadFile(const DownloadCreateInfo* info) render_view_id_(info->render_view_id), request_id_(info->request_id), bytes_so_far_(0), + full_path_(info->save_info.file_path), path_renamed_(false), in_progress_(true), - dont_sleep_(true) { + dont_sleep_(true), + save_info_(info->save_info) { } DownloadFile::~DownloadFile() { @@ -75,15 +77,15 @@ DownloadFile::~DownloadFile() { } bool DownloadFile::Initialize() { - if (file_util::CreateTemporaryFile(&full_path_)) - return Open("wb"); + if (!full_path_.empty() || file_util::CreateTemporaryFile(&full_path_)) + return Open(); return false; } bool DownloadFile::AppendDataToFile(const char* data, int data_len) { - if (file_) { + if (file_stream_.get()) { // FIXME bug 595247: handle errors on file writes. - size_t written = fwrite(data, 1, data_len, file_); + size_t written = file_stream_->Write(data, data_len, NULL); bytes_so_far_ += written; return true; } @@ -92,13 +94,18 @@ bool DownloadFile::AppendDataToFile(const char* data, int data_len) { void DownloadFile::Cancel() { Close(); - file_util::Delete(full_path_, false); + if (!full_path_.empty()) + file_util::Delete(full_path_, false); } // The UI has provided us with our finalized name. bool DownloadFile::Rename(const FilePath& new_path) { Close(); + // Nothing more to do if the new path is same as the old one. + if (new_path == full_path_) + return true; + #if defined(OS_WIN) // We cannot rename because rename will keep the same security descriptor // on the destination file. We want to recreate the security descriptor @@ -119,23 +126,30 @@ bool DownloadFile::Rename(const FilePath& new_path) { if (!in_progress_) return true; - if (!Open("a+b")) + if (!Open()) return false; return true; } void DownloadFile::Close() { - if (file_) { - file_util::CloseFile(file_); - file_ = NULL; + if (file_stream_.get()) { + file_stream_->Close(); + file_stream_.reset(); } } -bool DownloadFile::Open(const char* open_mode) { +bool DownloadFile::Open() { DCHECK(!full_path_.empty()); - file_ = file_util::OpenFile(full_path_, open_mode); - if (!file_) { - return false; + + // Create a new file steram if it is not provided. + if (!file_stream_.get()) { + file_stream_.reset(new net::FileStream); + if (file_stream_->Open(full_path_, + base::PLATFORM_FILE_OPEN_ALWAYS | + base::PLATFORM_FILE_WRITE) != net::OK) { + file_stream_.reset(); + return false; + } } #if defined(OS_WIN) @@ -429,7 +443,7 @@ void DownloadFileManager::DownloadUrl( const GURL& url, const GURL& referrer, const std::string& referrer_charset, - const FilePath& save_file_path, + const DownloadSaveInfo& save_info, int render_process_host_id, int render_view_id, URLRequestContextGetter* request_context_getter) { @@ -441,7 +455,7 @@ void DownloadFileManager::DownloadUrl( url, referrer, referrer_charset, - save_file_path, + save_info, render_process_host_id, render_view_id, request_context_getter)); @@ -526,7 +540,7 @@ void DownloadFileManager::OnDownloadUrl( const GURL& url, const GURL& referrer, const std::string& referrer_charset, - const FilePath& save_file_path, + const DownloadSaveInfo& save_info, int render_process_host_id, int render_view_id, URLRequestContextGetter* request_context_getter) { @@ -537,7 +551,7 @@ void DownloadFileManager::OnDownloadUrl( resource_dispatcher_host_->BeginDownload(url, referrer, - save_file_path, + save_info, render_process_host_id, render_view_id, context); diff --git a/chrome/browser/download/download_file.h b/chrome/browser/download/download_file.h index 352f937..d4df8c4 100644 --- a/chrome/browser/download/download_file.h +++ b/chrome/browser/download/download_file.h @@ -49,11 +49,13 @@ #include "base/basictypes.h" #include "base/file_path.h" #include "base/hash_tables.h" +#include "base/linked_ptr.h" #include "base/lock.h" #include "base/ref_counted.h" #include "base/timer.h" #include "chrome/browser/power_save_blocker.h" #include "googleurl/src/gurl.h" +#include "net/base/file_stream.h" namespace net { class IOBuffer; @@ -78,6 +80,16 @@ struct DownloadBuffer { std::vector<Contents> contents; }; +// DownloadSaveInfo ------------------------------------------------------------ + +// Holds the information about how to save a download file. +struct DownloadSaveInfo { + FilePath file_path; + linked_ptr<net::FileStream> file_stream; + + DownloadSaveInfo() { } +}; + // DownloadFile ---------------------------------------------------------------- // These objects live exclusively on the download thread and handle the writing @@ -111,18 +123,18 @@ class DownloadFile { int render_view_id() const { return render_view_id_; } int request_id() const { return request_id_; } bool path_renamed() const { return path_renamed_; } - bool in_progress() const { return file_ != NULL; } + bool in_progress() const { return file_stream_ != NULL; } void set_in_progress(bool in_progress) { in_progress_ = in_progress; } private: - // Open or Close the OS file handle. The file is opened in the constructor + // Open or Close the OS file stream. The stream is opened in the constructor // based on creation information passed to it, and automatically closed in // the destructor. void Close(); - bool Open(const char* open_mode); + bool Open(); - // OS file handle for writing - FILE* file_; + // OS file stream for writing + linked_ptr<net::FileStream> file_stream_; // Source URL for the file being downloaded. GURL source_url_; @@ -157,6 +169,9 @@ class DownloadFile { // RAII handle to keep the system from sleeping while we're downloading. PowerSaveBlocker dont_sleep_; + // The provider used to save the download data. + DownloadSaveInfo save_info_; + DISALLOW_COPY_AND_ASSIGN(DownloadFile); }; @@ -192,7 +207,7 @@ class DownloadFileManager void DownloadUrl(const GURL& url, const GURL& referrer, const std::string& referrer_charset, - const FilePath& save_file_path, + const DownloadSaveInfo& save_info, int render_process_host_id, int render_view_id, URLRequestContextGetter* request_context_getter); @@ -201,7 +216,7 @@ class DownloadFileManager void OnDownloadUrl(const GURL& url, const GURL& referrer, const std::string& referrer_charset, - const FilePath& save_file_path, + const DownloadSaveInfo& save_info, int render_process_host_id, int render_view_id, URLRequestContextGetter* request_context_getter); diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc index 1248d94..a69703b 100644 --- a/chrome/browser/download/download_manager.cc +++ b/chrome/browser/download/download_manager.cc @@ -598,21 +598,22 @@ void DownloadManager::StartDownload(DownloadCreateInfo* info) { info->save_as = true; } - // Determine the proper path for a download, by either one of the following: - // 1) using the provided save file path. - // 2) using the default download directory. - // 3) prompting the user. - FilePath generated_name; - GenerateFileNameFromInfo(info, &generated_name); - if (!info->save_file_path.empty()) - info->suggested_path = info->save_file_path; - else if (info->save_as && !last_download_path_.empty()) - info->suggested_path = last_download_path_; - else - info->suggested_path = download_path(); - info->suggested_path = info->suggested_path.Append(generated_name); + if (info->save_info.file_path.empty()) { + // Determine the proper path for a download, by either one of the following: + // 1) using the default download directory. + // 2) prompting the user. + FilePath generated_name; + GenerateFileNameFromInfo(info, &generated_name); + if (info->save_as && !last_download_path_.empty()) + info->suggested_path = last_download_path_; + else + info->suggested_path = download_path(); + info->suggested_path = info->suggested_path.Append(generated_name); + } else { + info->suggested_path = info->save_info.file_path; + } - if (!info->save_as && info->save_file_path.empty()) { + if (!info->save_as && info->save_info.file_path.empty()) { // Downloads can be marked as dangerous for two reasons: // a) They have a dangerous-looking filename // b) They are an extension that is not from the gallery @@ -646,7 +647,10 @@ void DownloadManager::CheckIfSuggestedPathExists(DownloadCreateInfo* info) { info->suggested_path = info->suggested_path.Append(filename); } - info->path_uniquifier = GetUniquePathNumber(info->suggested_path); + // Do not add the path uniquifier if we are saving to a specific path as in + // the drag-out case. + if (info->save_info.file_path.empty()) + info->path_uniquifier = GetUniquePathNumber(info->suggested_path); // If the download is deemed dangerous, we'll use a temporary name for it. if (info->is_dangerous) { @@ -676,7 +680,7 @@ void DownloadManager::CheckIfSuggestedPathExists(DownloadCreateInfo* info) { } } - if (!info->save_as) { + if (!info->save_as && info->save_info.file_path.empty()) { // Create an empty file at the suggested path so that we don't allocate the // same "non-existant" path to multiple downloads. // See: http://code.google.com/p/chromium/issues/detail?id=3662 @@ -743,7 +747,7 @@ void DownloadManager::ContinueStartDownload(DownloadCreateInfo* info, info->is_dangerous, info->save_as, info->is_extension_install, - !info->save_file_path.empty()); + !info->save_info.file_path.empty()); download->set_manager(this); in_progress_[info->download_id] = download; } else { @@ -1204,7 +1208,7 @@ void DownloadManager::DownloadUrl(const GURL& url, file_manager_->DownloadUrl(url, referrer, referrer_charset, - FilePath(), + DownloadSaveInfo(), tab_contents->GetRenderProcessHost()->id(), tab_contents->render_view_host()->routing_id(), request_context_getter_); @@ -1213,13 +1217,13 @@ void DownloadManager::DownloadUrl(const GURL& url, void DownloadManager::DownloadUrlToFile(const GURL& url, const GURL& referrer, const std::string& referrer_charset, - const FilePath& save_file_path, + const DownloadSaveInfo& save_info, TabContents* tab_contents) { DCHECK(tab_contents); file_manager_->DownloadUrl(url, referrer, referrer_charset, - save_file_path, + save_info, tab_contents->GetRenderProcessHost()->id(), tab_contents->render_view_host()->routing_id(), request_context_getter_); diff --git a/chrome/browser/download/download_manager.h b/chrome/browser/download/download_manager.h index 4d7a709..3ab0a53 100644 --- a/chrome/browser/download/download_manager.h +++ b/chrome/browser/download/download_manager.h @@ -62,6 +62,7 @@ class Profile; class ResourceDispatcherHost; class URLRequestContextGetter; class TabContents; +struct DownloadSaveInfo; namespace base { class Thread; @@ -414,7 +415,7 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>, void DownloadUrlToFile(const GURL& url, const GURL& referrer, const std::string& referrer_encoding, - const FilePath& save_file_path, + const DownloadSaveInfo& save_info, TabContents* tab_contents); // Allow objects to observe the download creation process. diff --git a/chrome/browser/download/drag_download_file.cc b/chrome/browser/download/drag_download_file.cc new file mode 100644 index 0000000..e55ccf5 --- /dev/null +++ b/chrome/browser/download/drag_download_file.cc @@ -0,0 +1,223 @@ +// Copyright (c) 2009-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 "chrome/browser/download/drag_download_file.h" + +#include "base/file_util.h" +#include "base/message_loop.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/download/download_file.h" +#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "net/base/file_stream.h" + +DragDownloadFile::DragDownloadFile( + const FilePath& file_name_or_path, + linked_ptr<net::FileStream> file_stream, + const GURL& url, + const GURL& referrer, + const std::string& referrer_encoding, + TabContents* tab_contents) + : file_stream_(file_stream), + url_(url), + referrer_(referrer), + referrer_encoding_(referrer_encoding), + tab_contents_(tab_contents), + drag_message_loop_(MessageLoop::current()), + is_started_(false), + is_successful_(false), + download_manager_(NULL), + download_item_observer_added_(false) { +#if defined(OS_WIN) + DCHECK(!file_name_or_path.empty() && !file_stream.get()); + file_name_ = file_name_or_path; +#elif defined(OS_MACOSX) + DCHECK(!file_name_or_path.empty() && file_stream.get()); + file_path_ = file_name_or_path; +#endif +} + +DragDownloadFile::~DragDownloadFile() { + AssertCurrentlyOnDragThread(); + + // Since the target application can still hold and use the dragged file, + // we do not know the time that it can be safely deleted. To solve this + // problem, we schedule it to be removed after the system is restarted. +#if defined(OS_WIN) + if (!temp_dir_path_.empty()) { + if (!file_path_.empty()) + file_util::DeleteAfterReboot(file_path_); + file_util::DeleteAfterReboot(temp_dir_path_); + } +#endif + + if (download_manager_) + download_manager_->RemoveObserver(this); +} + +bool DragDownloadFile::Start(DownloadFileObserver* observer) { + AssertCurrentlyOnDragThread(); + + if (is_started_) + return true; + is_started_ = true; + + DCHECK(!observer_.get()); + observer_ = observer; + + if (!file_stream_.get()) { + // Create a temporary directory to save the temporary download file. We do + // not want to use the default download directory since we do not want the + // twisted file name shown in the download shelf if the file with the same + // name already exists. + if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome"), + &temp_dir_path_)) + return false; + + file_path_ = temp_dir_path_.Append(file_name_); + } + + InitiateDownload(); + + // On Windows, we need to wait till the download file is completed. +#if defined(OS_WIN) + StartNestedMessageLoop(); +#endif + + return is_successful_; +} + +void DragDownloadFile::Stop() { +} + +void DragDownloadFile::InitiateDownload() { +#if defined(OS_WIN) + // DownloadManager could only be invoked from the UI thread. + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, + &DragDownloadFile::InitiateDownload)); + return; + } +#endif + + download_manager_ = tab_contents_->profile()->GetDownloadManager(); + download_manager_->AddObserver(this); + + DownloadSaveInfo save_info; + save_info.file_path = file_path_; + save_info.file_stream = file_stream_; + download_manager_->DownloadUrlToFile(url_, + referrer_, + referrer_encoding_, + save_info, + tab_contents_); +} + +void DragDownloadFile::DownloadCompleted(bool is_successful) { +#if defined(OS_WIN) + // If not in drag-and-drop thread, defer the running to it. + if (drag_message_loop_ != MessageLoop::current()) { + drag_message_loop_->PostTask( + FROM_HERE, + NewRunnableMethod(this, + &DragDownloadFile::DownloadCompleted, + is_successful)); + return; + } +#endif + + is_successful_ = is_successful; + + // Call the observer. + DCHECK(observer_); + if (is_successful) + observer_->OnDownloadCompleted(file_path_); + else + observer_->OnDownloadAborted(); + + // Release the observer since we do not need it any more. + observer_ = NULL; + + // On Windows, we need to stop the waiting. +#if defined(OS_WIN) + QuitNestedMessageLoop(); +#endif +} + +void DragDownloadFile::ModelChanged() { + AssertCurrentlyOnUIThread(); + + download_manager_->GetTemporaryDownloads(this, file_path_.DirName()); +} + +void DragDownloadFile::SetDownloads(std::vector<DownloadItem*>& downloads) { + AssertCurrentlyOnUIThread(); + + std::vector<DownloadItem*>::const_iterator it = downloads.begin(); + for (; it != downloads.end(); ++it) { + if (!download_item_observer_added_ && (*it)->url() == url_) { + download_item_observer_added_ = true; + (*it)->AddObserver(this); + } + } +} + +void DragDownloadFile::OnDownloadUpdated(DownloadItem* download) { + AssertCurrentlyOnUIThread(); + + if (download->state() == DownloadItem::CANCELLED) { + download->RemoveObserver(this); + download_manager_->RemoveObserver(this); + + DownloadCompleted(false); + } +} + +void DragDownloadFile::OnDownloadFileCompleted(DownloadItem* download) { + AssertCurrentlyOnUIThread(); + DCHECK(download->state() == DownloadItem::COMPLETE); + + download->RemoveObserver(this); + download_manager_->RemoveObserver(this); + + DownloadCompleted(true); +} + +void DragDownloadFile::AssertCurrentlyOnDragThread() { + // Only do the check on Windows where two threads are involved. +#if defined(OS_WIN) + DCHECK(drag_message_loop_ == MessageLoop::current()); +#endif +} + +void DragDownloadFile::AssertCurrentlyOnUIThread() { + // Only do the check on Windows where two threads are involved. +#if defined(OS_WIN) + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); +#endif +} + +#if defined(OS_WIN) +void DragDownloadFile::StartNestedMessageLoop() { + AssertCurrentlyOnDragThread(); + + bool old_state = MessageLoop::current()->NestableTasksAllowed(); + MessageLoop::current()->SetNestableTasksAllowed(true); + is_running_nested_message_loop_ = true; + MessageLoop::current()->Run(); + MessageLoop::current()->SetNestableTasksAllowed(old_state); +} + +void DragDownloadFile::QuitNestedMessageLoop() { + AssertCurrentlyOnDragThread(); + + if (is_running_nested_message_loop_) { + is_running_nested_message_loop_ = false; + MessageLoop::current()->Quit(); + } +} +#endif diff --git a/chrome/browser/download/drag_download_file.h b/chrome/browser/download/drag_download_file.h new file mode 100644 index 0000000..31064ec --- /dev/null +++ b/chrome/browser/download/drag_download_file.h @@ -0,0 +1,112 @@ +// Copyright (c) 2009-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 CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_FILE_H_ +#define CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_FILE_H_ + +#include "app/download_file_interface.h" +#include "base/file_path.h" +#include "base/linked_ptr.h" +#include "chrome/browser/download/download_file.h" +#include "chrome/browser/download/download_manager.h" +#include "googleurl/src/gurl.h" + +class TabContents; + +namespace net { +class FileSteram; +} + +class DragDownloadFile : public DownloadFileProvider, + public DownloadManager::Observer, + public DownloadItem::Observer { + public: + // On Windows, we need to download into a temporary file. Two threads are + // involved: background drag-and-drop thread and UI thread. + // The first parameter file_name_or_path should contain file name while the + // second parameter file_stream should be NULL. + // + // On MacOSX, we need to download into a file stream that has already been + // created. Only UI thread is involved. + // The file path and file stream should be provided as the first two + // parameters. + DragDownloadFile(const FilePath& file_name_or_path, + linked_ptr<net::FileStream> file_stream, + const GURL& url, + const GURL& referrer, + const std::string& referrer_encoding, + TabContents* tab_contents); + + // DownloadFileProvider methods. + // Called on drag-and-drop thread (Windows). + // Called on UI thread (MacOSX). + virtual bool Start(DownloadFileObserver* observer); + virtual void Stop(); +#if defined(OS_WIN) + virtual IStream* GetStream() { return NULL; } +#endif + + // DownloadManager::Observer methods. + // Called on UI thread. + virtual void ModelChanged(); + virtual void SetDownloads(std::vector<DownloadItem*>& downloads); + + // DownloadItem::Observer methods. + // Called on UI thread. + virtual void OnDownloadUpdated(DownloadItem* download); + virtual void OnDownloadFileCompleted(DownloadItem* download); + virtual void OnDownloadOpened(DownloadItem* download) { } + + private: + // Called on drag-and-drop thread (Windows). + // Called on UI thread (Windows). + virtual ~DragDownloadFile(); + + // Called on drag-and-drop thread (Windows only). +#if defined(OS_WIN) + void StartNestedMessageLoop(); + void QuitNestedMessageLoop(); +#endif + + // Called on either drag-and-drop thread or UI thread (Windows). + // Called on UI thread (MacOSX). + void InitiateDownload(); + void DownloadCompleted(bool is_successful); + + // Helper methods to make sure we're in the correct thread. + void AssertCurrentlyOnDragThread(); + void AssertCurrentlyOnUIThread(); + + // Initialized on drag-and-drop thread. Accessed on either thread after that + // (Windows). + // Accessed on UI thread (MacOSX). + FilePath file_path_; + FilePath file_name_; + linked_ptr<net::FileStream> file_stream_; + GURL url_; + GURL referrer_; + std::string referrer_encoding_; + TabContents* tab_contents_; + MessageLoop* drag_message_loop_; + FilePath temp_dir_path_; + + // Accessed on drag-and-drop thread (Windows). + // Accessed on UI thread (MacOSX). + bool is_started_; + bool is_successful_; + scoped_refptr<DownloadFileObserver> observer_; + + // Accessed on drag-and-drop thread (Windows only). +#if defined(OS_WIN) + bool is_running_nested_message_loop_; +#endif + + // Access on UI thread. + DownloadManager* download_manager_; + bool download_item_observer_added_; + + DISALLOW_COPY_AND_ASSIGN(DragDownloadFile); +}; + +#endif // CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_FILE_H_ diff --git a/chrome/browser/download/drag_download_file_win.cc b/chrome/browser/download/drag_download_file_win.cc deleted file mode 100644 index 77a9112..0000000 --- a/chrome/browser/download/drag_download_file_win.cc +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (c) 2009 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 "chrome/browser/download/drag_download_file_win.h" - -#include "base/file_util.h" -#include "base/message_loop.h" -#include "chrome/browser/chrome_thread.h" -#include "chrome/browser/download/download_manager.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/tab_contents/tab_contents.h" - -DragDownloadFile::DragDownloadFile( - const GURL& url, - const GURL& referrer, - const std::string& referrer_encoding, - TabContents* tab_contents) - : url_(url), - referrer_(referrer), - referrer_encoding_(referrer_encoding), - tab_contents_(tab_contents), - drag_message_loop_(MessageLoop::current()), - is_started_(false), - is_running_nested_message_loop_(false), - initiate_download_result_(false), - format_(0), - download_manager_(NULL), - download_item_observer_added_(false) { -} - -DragDownloadFile::~DragDownloadFile() { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - // Since the target application can still hold and use the dragged file, - // we do not know the time that it can be safely deleted. To solve this - // problem, we schedule it to be removed after the system is restarted. -#if defined(OS_WIN) - if (!dir_path_.empty()) { - if (!file_path_.empty()) - file_util::DeleteAfterReboot(file_path_); - file_util::DeleteAfterReboot(dir_path_); - } -#endif - - if (download_manager_) - download_manager_->RemoveObserver(this); -} - -bool DragDownloadFile::Start(OSExchangeData::DownloadFileObserver* observer, - int format) { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - if (is_started_) - return true; - is_started_ = true; - - DCHECK(!observer_.get()); - observer_ = observer; - format_ = format; - - if (!InitiateDownload()) - return false; - - // Wait till the download is fully initiated. - StartNestedMessageLoop(); - - return initiate_download_result_; -} - -void DragDownloadFile::Stop() { -} - -bool DragDownloadFile::InitiateDownload() { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - // Create a temporary directory to save the temporary download file. We do - // not want to use the default download directory since we do not want the - // twisted file name shown in the download shelf if the file with the same - // name already exists. - if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome"), - &dir_path_)) - return false; - - // DownloadManager could only be invoked from the UI thread. - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod(this, - &DragDownloadFile::OnInitiateDownload, - dir_path_)); - - return true; -} - -void DragDownloadFile::OnInitiateDownload(const FilePath& dir_path) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - - download_manager_ = tab_contents_->profile()->GetDownloadManager(); - download_manager_->AddObserver(this); - - // Start the download. - download_manager_->DownloadUrlToFile(url_, - referrer_, - referrer_encoding_, - dir_path, - tab_contents_); -} - -void DragDownloadFile::InitiateDownloadSucceeded( - const std::vector<OSExchangeData::DownloadFileInfo*>& downloads) { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - // Notify the drag-and-drop observer about the file info. - DCHECK(observer_); - observer_->OnDataReady(format_, downloads); - - InitiateDownloadCompleted(true); -} - -void DragDownloadFile::InitiateDownloadFailed() { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - InitiateDownloadCompleted(false); -} - -void DragDownloadFile::InitiateDownloadCompleted(bool result) { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - // Release the observer since we do not need it any more. - observer_ = NULL; - - initiate_download_result_ = result; - QuitNestedMessageLoopIfNeeded(); -} - -void DragDownloadFile::StartNestedMessageLoop() { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - bool old_state = MessageLoop::current()->NestableTasksAllowed(); - MessageLoop::current()->SetNestableTasksAllowed(true); - is_running_nested_message_loop_ = true; - MessageLoop::current()->Run(); - MessageLoop::current()->SetNestableTasksAllowed(old_state); -} - -void DragDownloadFile::QuitNestedMessageLoopIfNeeded() { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - if (is_running_nested_message_loop_) { - is_running_nested_message_loop_ = false; - MessageLoop::current()->Quit(); - } -} - -void DragDownloadFile::ModelChanged() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - - download_manager_->GetTemporaryDownloads(this, dir_path_); -} - -void DragDownloadFile::SetDownloads(std::vector<DownloadItem*>& downloads) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - - std::vector<DownloadItem*>::const_iterator it = downloads.begin(); - for (; it != downloads.end(); ++it) { - if (!download_item_observer_added_ && (*it)->url() == url_) { - download_item_observer_added_ = true; - (*it)->AddObserver(this); - } - } -} - -void DragDownloadFile::OnDownloadUpdated(DownloadItem* download) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - - if (download->state() == DownloadItem::CANCELLED) { - download->RemoveObserver(this); - download_manager_->RemoveObserver(this); - - drag_message_loop_->PostTask( - FROM_HERE, - NewRunnableMethod(this, - &DragDownloadFile::DownloadCancelled)); - } -} - -void DragDownloadFile::OnDownloadFileCompleted(DownloadItem* download) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - DCHECK(download->state() == DownloadItem::COMPLETE); - - download->RemoveObserver(this); - download_manager_->RemoveObserver(this); - - drag_message_loop_->PostTask( - FROM_HERE, - NewRunnableMethod(this, - &DragDownloadFile::DownloadCompleted, - download->full_path())); -} - -void DragDownloadFile::DownloadCancelled() { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - InitiateDownloadFailed(); -} - -void DragDownloadFile::DownloadCompleted(const FilePath& file_path) { - DCHECK(drag_message_loop_ == MessageLoop::current()); - - file_path_ = file_path; - - // The download has been successfully initiated. - std::vector<OSExchangeData::DownloadFileInfo*> downloads; - downloads.push_back( - new OSExchangeData::DownloadFileInfo(file_path, 0, NULL)); - InitiateDownloadSucceeded(downloads); -} diff --git a/chrome/browser/download/drag_download_file_win.h b/chrome/browser/download/drag_download_file_win.h deleted file mode 100644 index a1ef5ed..0000000 --- a/chrome/browser/download/drag_download_file_win.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2009 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 CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_FILE_WIN_H_ -#define CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_FILE_WIN_H_ - -#include "app/os_exchange_data.h" -#include "base/file_path.h" -#include "chrome/browser/download/download_manager.h" -#include "googleurl/src/gurl.h" - -class TabContents; - -class DragDownloadFile : public OSExchangeData::DownloadFileProvider, - public DownloadManager::Observer, - public DownloadItem::Observer { - public: - DragDownloadFile(const GURL& url, - const GURL& referrer, - const std::string& referrer_encoding, - TabContents* tab_contents); - - // OSExchangeData::DownloadFileProvider methods. - // Called on drag-and-drop thread. - virtual bool Start(OSExchangeData::DownloadFileObserver* observer, - int format); - virtual void Stop(); - - // DownloadManager::Observer methods. - // Called on UI thread. - virtual void ModelChanged(); - virtual void SetDownloads(std::vector<DownloadItem*>& downloads); - - // DownloadItem::Observer methods. - // Called on UI thread. - virtual void OnDownloadUpdated(DownloadItem* download); - virtual void OnDownloadFileCompleted(DownloadItem* download); - virtual void OnDownloadOpened(DownloadItem* download) { } - - private: - // Called on drag-and-drop thread. - virtual ~DragDownloadFile(); - - bool InitiateDownload(); - void InitiateDownloadSucceeded( - const std::vector<OSExchangeData::DownloadFileInfo*>& downloads); - void InitiateDownloadFailed(); - void InitiateDownloadCompleted(bool result); - - void DownloadCancelled(); - void DownloadCompleted(const FilePath& file_path); - - void StartNestedMessageLoop(); - void QuitNestedMessageLoopIfNeeded(); - - // Called on UI thread. - void OnInitiateDownload(const FilePath& dir_path); - void CheckDownloadStatus(DownloadItem* download); - - // Initialized on drag-and-drop thread. Can be accessed on either thread. - GURL url_; - GURL referrer_; - std::string referrer_encoding_; - TabContents* tab_contents_; - MessageLoop* drag_message_loop_; - - // Accessed on drag-and-drop thread. - bool is_started_; - bool is_running_nested_message_loop_; - bool initiate_download_result_; - scoped_refptr<OSExchangeData::DownloadFileObserver> observer_; - int format_; - FilePath dir_path_; - FilePath file_path_; - - // Access on UI thread. - DownloadManager* download_manager_; - bool download_item_observer_added_; - - DISALLOW_COPY_AND_ASSIGN(DragDownloadFile); -}; - -#endif // CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_FILE_WIN_H_ diff --git a/chrome/browser/download/drag_download_util.cc b/chrome/browser/download/drag_download_util.cc new file mode 100644 index 0000000..ed34e70 --- /dev/null +++ b/chrome/browser/download/drag_download_util.cc @@ -0,0 +1,48 @@ +// 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 "chrome/browser/download/drag_download_util.h" + +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "googleurl/src/gurl.h" + +namespace drag_download_util { + +bool ParseDownloadMetadata(const string16& metadata, + string16* mime_type, + FilePath* file_name, + GURL* url) { + const char16 separator = L':'; + + size_t mime_type_end_pos = metadata.find(separator); + if (mime_type_end_pos == string16::npos) + return false; + + size_t file_name_end_pos = metadata.find(separator, mime_type_end_pos + 1); + if (file_name_end_pos == string16::npos) + return false; + + GURL parsed_url = GURL(metadata.substr(file_name_end_pos + 1)); + if (!parsed_url.is_valid()) + return false; + + if (mime_type) + *mime_type = metadata.substr(0, mime_type_end_pos); + if (file_name) { + string16 file_name_str = metadata.substr( + mime_type_end_pos + 1, file_name_end_pos - mime_type_end_pos - 1); +#if defined(OS_WIN) + *file_name = FilePath(file_name_str); +#else + *file_name = FilePath(UTF16ToUTF8(file_name_str)); +#endif + } + if (url) + *url = parsed_url; + + return true; +} + +} // namespace drag_download_util diff --git a/chrome/browser/download/drag_download_util.h b/chrome/browser/download/drag_download_util.h new file mode 100644 index 0000000..7f2a853 --- /dev/null +++ b/chrome/browser/download/drag_download_util.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 CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_UTIL_H_ +#define CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_UTIL_H_ + +#include "base/basictypes.h" +#include "base/file_path.h" + +class GURL; + +namespace drag_download_util { + +// Parse the download metadata set in DataTransfer.setData. The metadata +// consists of a set of the following values separated by ":" +// * MIME type +// * File name +// * URL +// For example, we can have +// text/plain:example.txt:http://example.com/example.txt +bool ParseDownloadMetadata(const string16& metadata, + string16* mime_type, + FilePath* file_name, + GURL* url); + +} // namespace drag_download_util + +#endif // CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_UTIL_H_ diff --git a/chrome/browser/history/download_types.h b/chrome/browser/history/download_types.h index 7025b1d..50c7e26 100644 --- a/chrome/browser/history/download_types.h +++ b/chrome/browser/history/download_types.h @@ -12,6 +12,7 @@ #include "base/basictypes.h" #include "base/file_path.h" #include "base/time.h" +#include "chrome/browser/download/download_file.h" #include "googleurl/src/gurl.h" // Used for informing the download database of a new download, where we don't @@ -87,8 +88,8 @@ struct DownloadCreateInfo { // 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 file path to save to. - FilePath save_file_path; + // The download file save info. + DownloadSaveInfo save_info; }; #endif // CHROME_BROWSER_HISTORY_DOWNLOAD_TYPES_H_ diff --git a/chrome/browser/renderer_host/download_resource_handler.cc b/chrome/browser/renderer_host/download_resource_handler.cc index e414587..1bbb757 100644 --- a/chrome/browser/renderer_host/download_resource_handler.cc +++ b/chrome/browser/renderer_host/download_resource_handler.cc @@ -13,15 +13,16 @@ #include "net/base/io_buffer.h" #include "net/url_request/url_request_context.h" -DownloadResourceHandler::DownloadResourceHandler(ResourceDispatcherHost* rdh, - int render_process_host_id, - int render_view_id, - int request_id, - const GURL& url, - DownloadFileManager* manager, - URLRequest* request, - bool save_as, - const FilePath& save_file_path) +DownloadResourceHandler::DownloadResourceHandler( + ResourceDispatcherHost* rdh, + int render_process_host_id, + int render_view_id, + int request_id, + const GURL& url, + DownloadFileManager* manager, + URLRequest* request, + bool save_as, + const DownloadSaveInfo& save_info) : download_id_(-1), global_id_(render_process_host_id, request_id), render_view_id_(render_view_id), @@ -30,7 +31,7 @@ DownloadResourceHandler::DownloadResourceHandler(ResourceDispatcherHost* rdh, download_manager_(manager), request_(request), save_as_(save_as), - save_file_path_(save_file_path), + save_info_(save_info), buffer_(new DownloadBuffer), rdh_(rdh), is_paused_(false) { @@ -69,10 +70,10 @@ bool DownloadResourceHandler::OnResponseStarted(int request_id, info->request_id = global_id_.request_id; info->content_disposition = content_disposition_; info->mime_type = response->response_head.mime_type; - info->save_as = save_as_ && save_file_path_.empty(); + info->save_as = save_as_ && save_info_.file_path.empty(); info->is_dangerous = false; info->referrer_charset = request_->context()->referrer_charset(); - info->save_file_path = save_file_path_; + info->save_info = save_info_; ChromeThread::PostTask( ChromeThread::FILE, FROM_HERE, NewRunnableMethod( diff --git a/chrome/browser/renderer_host/download_resource_handler.h b/chrome/browser/renderer_host/download_resource_handler.h index 59b4cb4..bb8d9cd 100644 --- a/chrome/browser/renderer_host/download_resource_handler.h +++ b/chrome/browser/renderer_host/download_resource_handler.h @@ -9,6 +9,7 @@ #include "base/file_path.h" #include "base/timer.h" +#include "chrome/browser/download/download_file.h" #include "chrome/browser/renderer_host/global_request_id.h" #include "chrome/browser/renderer_host/resource_handler.h" @@ -28,7 +29,7 @@ class DownloadResourceHandler : public ResourceHandler { DownloadFileManager* manager, URLRequest* request, bool save_as, - const FilePath& save_file_path); + const DownloadSaveInfo& save_info); // Not needed, as this event handler ought to be the final resource. bool OnRequestRedirected(int request_id, const GURL& url, @@ -72,7 +73,7 @@ class DownloadResourceHandler : public ResourceHandler { DownloadFileManager* download_manager_; URLRequest* request_; bool save_as_; // Request was initiated via "Save As" by the user. - FilePath save_file_path_; + DownloadSaveInfo save_info_; DownloadBuffer* buffer_; ResourceDispatcherHost* rdh_; bool is_paused_; diff --git a/chrome/browser/renderer_host/download_throttling_resource_handler.cc b/chrome/browser/renderer_host/download_throttling_resource_handler.cc index 4b02880..87314dc 100644 --- a/chrome/browser/renderer_host/download_throttling_resource_handler.cc +++ b/chrome/browser/renderer_host/download_throttling_resource_handler.cc @@ -130,7 +130,6 @@ void DownloadThrottlingResourceHandler::CancelDownload() { void DownloadThrottlingResourceHandler::ContinueDownload() { DCHECK(!download_handler_.get()); - FilePath save_file_path; download_handler_ = new DownloadResourceHandler(host_, render_process_host_id_, @@ -140,7 +139,7 @@ void DownloadThrottlingResourceHandler::ContinueDownload() { host_->download_file_manager(), request_, false, - save_file_path); + DownloadSaveInfo()); if (response_.get()) download_handler_->OnResponseStarted(request_id_, response_.get()); diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc index 971888c..b92c6a9 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.cc +++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc @@ -560,12 +560,13 @@ void ResourceDispatcherHost::OnClosePageACK( } // We are explicitly forcing the download of 'url'. -void ResourceDispatcherHost::BeginDownload(const GURL& url, - const GURL& referrer, - const FilePath& save_file_path, - int child_id, - int route_id, - URLRequestContext* request_context) { +void ResourceDispatcherHost::BeginDownload( + const GURL& url, + const GURL& referrer, + const DownloadSaveInfo& save_info, + int child_id, + int route_id, + URLRequestContext* request_context) { if (is_shutdown_) return; @@ -593,7 +594,7 @@ void ResourceDispatcherHost::BeginDownload(const GURL& url, download_file_manager_.get(), request, true, - save_file_path); + save_info); if (safe_browsing_->enabled() && safe_browsing_->CanCheckUrl(url)) { diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h index 4e10dae..c410f3a 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.h +++ b/chrome/browser/renderer_host/resource_dispatcher_host.h @@ -42,6 +42,7 @@ class SSLClientAuthHandler; class UserScriptListener; class URLRequestContext; class WebKitThread; +struct DownloadSaveInfo; struct GlobalRequestID; struct ViewHostMsg_Resource_Request; struct ViewMsg_ClosePage_Params; @@ -107,7 +108,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate { // request from the renderer or another child process). void BeginDownload(const GURL& url, const GURL& referrer, - const FilePath& save_file_path, + const DownloadSaveInfo& save_info, int process_unique_id, int route_id, URLRequestContext* request_context); diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 2c04259..ae3ddd4 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -15,6 +15,7 @@ #include "chrome/browser/child_process_security_policy.h" #include "chrome/browser/chrome_plugin_browsing_context.h" #include "chrome/browser/chrome_thread.h" +#include "chrome/browser/download/download_file.h" #include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/host_zoom_map.h" @@ -778,10 +779,9 @@ void ResourceMessageFilter::OnDownloadUrl(const IPC::Message& message, const GURL& url, const GURL& referrer) { URLRequestContext* context = request_context_->GetURLRequestContext(); - FilePath save_file_path; resource_dispatcher_host_->BeginDownload(url, referrer, - save_file_path, + DownloadSaveInfo(), id(), message.routing_id(), context); diff --git a/chrome/browser/views/tab_contents/tab_contents_drag_win.cc b/chrome/browser/views/tab_contents/tab_contents_drag_win.cc index 013dd40..59ddfd3 100644 --- a/chrome/browser/views/tab_contents/tab_contents_drag_win.cc +++ b/chrome/browser/views/tab_contents/tab_contents_drag_win.cc @@ -10,10 +10,12 @@ #include "base/message_loop.h" #include "base/task.h" #include "base/thread.h" +#include "base/utf_string_conversions.h" #include "base/win_util.h" #include "chrome/browser/bookmarks/bookmark_drag_data.h" #include "chrome/browser/chrome_thread.h" -#include "chrome/browser/download/drag_download_file_win.h" +#include "chrome/browser/download/drag_download_file.h" +#include "chrome/browser/download/drag_download_util.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/web_drag_source_win.h" @@ -112,7 +114,7 @@ void TabContentsDragWin::StartDragging(const WebDropData& drop_data, const std::string& page_encoding = view_->tab_contents()->encoding(); // If it is not drag-out, do the drag-and-drop in the current UI thread. - if (!drop_data.download_url.is_valid()) { + if (drop_data.download_metadata.empty()) { DoDragging(drop_data, ops, page_url, page_encoding); EndDragging(false); return; @@ -171,17 +173,38 @@ void TabContentsDragWin::PrepareDragForDownload( OSExchangeData* data, const GURL& page_url, const std::string& page_encoding) { + // Parse the download metadata. + string16 mime_type; + FilePath file_name; + GURL download_url; + if (!drag_download_util::ParseDownloadMetadata(drop_data.download_metadata, + &mime_type, + &file_name, + &download_url)) + return; + + // Generate the download filename. + std::string content_disposition = + "attachment; filename=" + UTF16ToUTF8(file_name.value()); + FilePath generated_file_name; + DownloadManager::GenerateFileName(download_url, + content_disposition, + std::string(), + UTF16ToUTF8(mime_type), + &generated_file_name); + // Provide the data as file (CF_HDROP). A temporary download file with the // Zone.Identifier ADS (Alternate Data Stream) attached will be created. + linked_ptr<net::FileStream> empty_file_stream; scoped_refptr<DragDownloadFile> download_file = - new DragDownloadFile(drop_data.download_url, + new DragDownloadFile(generated_file_name, + empty_file_stream, + download_url, page_url, page_encoding, view_->tab_contents()); - OSExchangeData::DownloadFileInfo* file_download = - new OSExchangeData::DownloadFileInfo(FilePath(), - 0, - download_file.get()); + OSExchangeData::DownloadFileInfo file_download(FilePath(), + download_file.get()); data->SetDownloadFileInfo(file_download); // Enable asynchronous operation. @@ -238,7 +261,7 @@ void TabContentsDragWin::DoDragging(const WebDropData& drop_data, // TODO(tc): Generate an appropriate drag image. - if (drop_data.download_url.is_valid()) { + if (!drop_data.download_metadata.empty()) { PrepareDragForDownload(drop_data, &data, page_url, page_encoding); // Set the observer. diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 94a563e..f149430 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -728,8 +728,10 @@ 'browser/download/download_started_animation.h', 'browser/download/download_util.cc', 'browser/download/download_util.h', - 'browser/download/drag_download_file_win.cc', - 'browser/download/drag_download_file_win.h', + 'browser/download/drag_download_file.cc', + 'browser/download/drag_download_file.h', + 'browser/download/drag_download_util.cc', + 'browser/download/drag_download_util.h', 'browser/download/save_file.cc', 'browser/download/save_file.h', 'browser/download/save_file_manager.cc', diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index d985d2d..8c2eaed 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -1790,7 +1790,7 @@ struct ParamTraits<WebDropData> { WriteParam(m, p.identity); WriteParam(m, p.url); WriteParam(m, p.url_title); - WriteParam(m, p.download_url); + WriteParam(m, p.download_metadata); WriteParam(m, p.file_extension); WriteParam(m, p.filenames); WriteParam(m, p.plain_text); @@ -1804,7 +1804,7 @@ struct ParamTraits<WebDropData> { ReadParam(m, iter, &p->identity) && ReadParam(m, iter, &p->url) && ReadParam(m, iter, &p->url_title) && - ReadParam(m, iter, &p->download_url) && + ReadParam(m, iter, &p->download_metadata) && ReadParam(m, iter, &p->file_extension) && ReadParam(m, iter, &p->filenames) && ReadParam(m, iter, &p->plain_text) && diff --git a/webkit/glue/webdropdata.cc b/webkit/glue/webdropdata.cc index bf2de89..d46987a 100644 --- a/webkit/glue/webdropdata.cc +++ b/webkit/glue/webdropdata.cc @@ -19,7 +19,7 @@ WebDropData::WebDropData(const WebDragData& drag_data) : identity(0), url(drag_data.url()), url_title(drag_data.urlTitle()), - download_url(drag_data.downloadURL()), + download_metadata(drag_data.downloadMetadata()), file_extension(drag_data.fileExtension()), plain_text(drag_data.plainText()), text_html(drag_data.htmlText()), diff --git a/webkit/glue/webdropdata.h b/webkit/glue/webdropdata.h index 96edfea..8149d8e 100644 --- a/webkit/glue/webdropdata.h +++ b/webkit/glue/webdropdata.h @@ -39,7 +39,7 @@ struct WebDropData { string16 url_title; // The title associated with |url|. // User is dragging a link out-of the webview. - GURL download_url; + string16 download_metadata; // File extension for dragging images from a webview to the desktop. string16 file_extension; |