summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-10 00:00:32 +0000
committerjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-10 00:00:32 +0000
commit8af9d0341d6c00ee537adc089f938b120d1d8d34 (patch)
tree334fcf5a09c2b3e12face9d46ae4f25ee62921eb
parent8d292399e6dcdfa776a1de94da07841bf1487f5b (diff)
downloadchromium_src-8af9d0341d6c00ee537adc089f938b120d1d8d34.zip
chromium_src-8af9d0341d6c00ee537adc089f938b120d1d8d34.tar.gz
chromium_src-8af9d0341d6c00ee537adc089f938b120d1d8d34.tar.bz2
Refactor DragDownloadFile so that it can be used by both Windows and MacOSX.
BUG=none TEST=none Review URL: http://codereview.chromium.org/572014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38545 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--app/app_base.gypi1
-rw-r--r--app/download_file_interface.h46
-rw-r--r--app/os_exchange_data.cc2
-rw-r--r--app/os_exchange_data.h40
-rw-r--r--app/os_exchange_data_provider_win.cc71
-rw-r--r--app/os_exchange_data_provider_win.h18
-rw-r--r--chrome/browser/download/download_file.cc52
-rw-r--r--chrome/browser/download/download_file.h29
-rw-r--r--chrome/browser/download/download_manager.cc44
-rw-r--r--chrome/browser/download/download_manager.h3
-rw-r--r--chrome/browser/download/drag_download_file.cc223
-rw-r--r--chrome/browser/download/drag_download_file.h112
-rw-r--r--chrome/browser/download/drag_download_file_win.cc217
-rw-r--r--chrome/browser/download/drag_download_file_win.h84
-rw-r--r--chrome/browser/download/drag_download_util.cc48
-rw-r--r--chrome/browser/download/drag_download_util.h29
-rw-r--r--chrome/browser/history/download_types.h5
-rw-r--r--chrome/browser/renderer_host/download_resource_handler.cc25
-rw-r--r--chrome/browser/renderer_host/download_resource_handler.h5
-rw-r--r--chrome/browser/renderer_host/download_throttling_resource_handler.cc3
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc15
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.h3
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc4
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_drag_win.cc39
-rwxr-xr-xchrome/chrome_browser.gypi6
-rw-r--r--chrome/common/render_messages.h4
-rw-r--r--webkit/glue/webdropdata.cc2
-rw-r--r--webkit/glue/webdropdata.h2
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;