diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-14 23:41:28 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-14 23:41:28 +0000 |
commit | 0ffaa48416edf9bbb6a1ccac8df6aa4eec6255aa (patch) | |
tree | cc653d2995ebd5174e7308d976d3625d49fc05e2 /chrome/browser | |
parent | ae57efd76a9bf4bb4d01b009e38d7f7c9b2f9e00 (diff) | |
download | chromium_src-0ffaa48416edf9bbb6a1ccac8df6aa4eec6255aa.zip chromium_src-0ffaa48416edf9bbb6a1ccac8df6aa4eec6255aa.tar.gz chromium_src-0ffaa48416edf9bbb6a1ccac8df6aa4eec6255aa.tar.bz2 |
Move the save file code from chrome to content. This is just a file move so the DEPS in content\browser\download is very permissive for now. The one exception is save_package.cc, where I had to split off the usage of SelectFileDialog because the code depended on grit which can't be used in content (circular dependencies in gyp).
TBR=rdsmith
BUG=82782
Review URL: http://codereview.chromium.org/7373004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92623 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
34 files changed, 236 insertions, 4233 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index eb9f6df..058fb3b 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -42,7 +42,6 @@ #include "chrome/browser/content_settings/host_content_settings_map.h" #include "chrome/browser/dom_operation_notification_details.h" #include "chrome/browser/download/download_item.h" -#include "chrome/browser/download/save_package.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_host.h" @@ -81,6 +80,7 @@ #include "chrome/common/url_constants.h" #include "content/browser/browser_thread.h" #include "content/browser/debugger/devtools_manager.h" +#include "content/browser/download/save_package.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/ssl/ssl_manager.h" diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc index 9c0a3f9..1281a6b 100644 --- a/chrome/browser/automation/automation_provider_observers.cc +++ b/chrome/browser/automation/automation_provider_observers.cc @@ -26,7 +26,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/dom_operation_notification_details.h" #include "chrome/browser/download/download_item.h" -#include "chrome/browser/download/save_package.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" @@ -63,6 +62,7 @@ #include "chrome/common/automation_messages.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/extensions/extension.h" +#include "content/browser/download/save_package.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/tab_contents/navigation_controller.h" diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc index b7eccd8..e003231 100644 --- a/chrome/browser/automation/testing_automation_provider.cc +++ b/chrome/browser/automation/testing_automation_provider.cc @@ -43,7 +43,7 @@ #include "chrome/browser/browser_shutdown.h" #include "chrome/browser/content_settings/host_content_settings_map.h" #include "chrome/browser/download/download_prefs.h" -#include "chrome/browser/download/save_package.h" +#include "chrome/browser/download/save_package_file_picker.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_updater.h" @@ -97,6 +97,7 @@ #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "content/browser/debugger/devtools_window.h" +#include "content/browser/download/save_package.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/tab_contents/interstitial_page.h" @@ -2063,7 +2064,7 @@ void TestingAutomationProvider::GoForwardBlockUntilNavigationsComplete( void TestingAutomationProvider::SavePackageShouldPromptUser( bool should_prompt) { - SavePackage::SetShouldPromptUser(should_prompt); + SavePackageFilePicker::SetShouldPromptUser(should_prompt); } void TestingAutomationProvider::SetShelfVisibility(int handle, bool visible) { diff --git a/chrome/browser/browser_encoding_uitest.cc b/chrome/browser/browser_encoding_uitest.cc index 46e5a2a..d7fe2dc 100644 --- a/chrome/browser/browser_encoding_uitest.cc +++ b/chrome/browser/browser_encoding_uitest.cc @@ -5,13 +5,13 @@ #include "base/file_util.h" #include "base/scoped_temp_dir.h" -#include "chrome/browser/download/save_package.h" #include "chrome/common/pref_names.h" #include "chrome/test/automation/automation_proxy.h" #include "chrome/test/automation/browser_proxy.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/ui/ui_test.h" #include "chrome/test/ui_test_utils.h" +#include "content/browser/download/save_package.h" #include "content/browser/net/url_request_mock_http_job.h" static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("encoding_tests"); diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 21d502e..225bbb7 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -22,7 +22,6 @@ #include "chrome/browser/browser_trial.h" #include "chrome/browser/download/download_file_manager.h" #include "chrome/browser/download/mhtml_generation_manager.h" -#include "chrome/browser/download/save_file_manager.h" #include "chrome/browser/extensions/extension_event_router_forwarder.h" #include "chrome/browser/extensions/extension_tab_id_map.h" #include "chrome/browser/extensions/user_script_listener.h" @@ -72,6 +71,7 @@ #include "content/browser/debugger/devtools_http_protocol_handler.h" #include "content/browser/debugger/devtools_manager.h" #include "content/browser/debugger/devtools_protocol_handler.h" +#include "content/browser/download/save_file_manager.h" #include "content/browser/gpu/gpu_process_host_ui_shim.h" #include "content/browser/net/browser_online_state_observer.h" #include "content/browser/plugin_service.h" diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 9758443..7cce656 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -15,6 +15,7 @@ #include "chrome/browser/chrome_worker_message_filter.h" #include "chrome/browser/content_settings/host_content_settings_map.h" #include "chrome/browser/content_settings/tab_specific_content_settings.h" +#include "chrome/browser/download/save_package_file_picker.h" #include "chrome/browser/extensions/extension_info_map.h" #include "chrome/browser/extensions/extension_message_handler.h" #include "chrome/browser/extensions/extension_service.h" @@ -710,6 +711,15 @@ void ChromeContentBrowserClient::ClearCookies(RenderViewHost* rvh) { // BrowsingDataRemover takes care of deleting itself when done. } +void ChromeContentBrowserClient::ChooseSavePath( + SavePackage* save_package, + const FilePath& suggested_path, + bool can_save_as_complete) { + // Deletes itself. + new SavePackageFilePicker( + save_package, suggested_path, can_save_as_complete); +} + #if defined(OS_LINUX) int ChromeContentBrowserClient::GetCrashSignalFD( const std::string& process_type) { diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index edc23d9..a55cfa6 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h @@ -100,8 +100,11 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient { const std::string& value) OVERRIDE; virtual void ClearInspectorSettings(RenderViewHost* rvh) OVERRIDE; virtual void BrowserURLHandlerCreated(BrowserURLHandler* handler) OVERRIDE; - virtual void ClearCache(RenderViewHost* rvh); - virtual void ClearCookies(RenderViewHost* rvh); + virtual void ClearCache(RenderViewHost* rvh) OVERRIDE; + virtual void ClearCookies(RenderViewHost* rvh) OVERRIDE; + virtual void ChooseSavePath(SavePackage* save_package, + const FilePath& suggested_path, + bool can_save_as_complete) OVERRIDE; #if defined(OS_POSIX) && !defined(OS_MACOSX) // Can return an optional fd for crash handling, otherwise returns -1. diff --git a/chrome/browser/download/base_file.cc b/chrome/browser/download/base_file.cc deleted file mode 100644 index e52f08a..0000000 --- a/chrome/browser/download/base_file.cc +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/download/base_file.h" - -#include "base/file_util.h" -#include "base/format_macros.h" -#include "base/logging.h" -#include "base/stringprintf.h" -#include "base/utf_string_conversions.h" -#include "crypto/secure_hash.h" -#include "net/base/file_stream.h" -#include "net/base/net_errors.h" -#include "chrome/browser/download/download_util.h" -#include "content/browser/browser_thread.h" - -#if defined(OS_WIN) -#include "chrome/common/win_safe_util.h" -#elif defined(OS_MACOSX) -#include "chrome/browser/mac/file_metadata.h" -#endif - -BaseFile::BaseFile(const FilePath& full_path, - const GURL& source_url, - const GURL& referrer_url, - int64 received_bytes, - const linked_ptr<net::FileStream>& file_stream) - : full_path_(full_path), - source_url_(source_url), - referrer_url_(referrer_url), - file_stream_(file_stream), - bytes_so_far_(received_bytes), - power_save_blocker_(true), - calculate_hash_(false), - detached_(false) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - memset(sha256_hash_, 0, sizeof(sha256_hash_)); -} - -BaseFile::~BaseFile() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - if (detached_) - Close(); - else - Cancel(); // Will delete the file. -} - -bool BaseFile::Initialize(bool calculate_hash) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(!detached_); - - calculate_hash_ = calculate_hash; - - if (calculate_hash_) - secure_hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256)); - - if (!full_path_.empty() || - download_util::CreateTemporaryFileForDownload(&full_path_)) - return Open(); - return false; -} - -bool BaseFile::AppendDataToFile(const char* data, size_t data_len) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(!detached_); - - if (!file_stream_.get()) - return false; - - // TODO(phajdan.jr): get rid of this check. - if (data_len == 0) - return true; - - bytes_so_far_ += data_len; - - // TODO(phajdan.jr): handle errors on file writes. http://crbug.com/58355 - size_t written = file_stream_->Write(data, data_len, NULL); - if (written != data_len) - return false; - - if (calculate_hash_) - secure_hash_->Update(data, data_len); - - return true; -} - -bool BaseFile::Rename(const FilePath& new_path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - // Save the information whether the download is in progress because - // it will be overwritten by closing the file. - bool saved_in_progress = in_progress(); - - // If the new path is same as the old one, there is no need to perform the - // following renaming logic. - if (new_path == full_path_) { - // Don't close the file if we're not done (finished or canceled). - if (!saved_in_progress) - Close(); - - return true; - } - - Close(); - - file_util::CreateDirectory(new_path.DirName()); - -#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 - // with the security that makes sense in the new path. - if (!file_util::RenameFileAndResetSecurityDescriptor(full_path_, new_path)) - return false; -#elif defined(OS_POSIX) - { - // Similarly, on Unix, we're moving a temp file created with permissions - // 600 to |new_path|. Here, we try to fix up the destination file with - // appropriate permissions. - struct stat st; - // First check the file existence and create an empty file if it doesn't - // exist. - if (!file_util::PathExists(new_path)) - file_util::WriteFile(new_path, "", 0); - bool stat_succeeded = (stat(new_path.value().c_str(), &st) == 0); - - // TODO(estade): Move() falls back to copying and deleting when a simple - // rename fails. Copying sucks for large downloads. crbug.com/8737 - if (!file_util::Move(full_path_, new_path)) - return false; - - if (stat_succeeded) - chmod(new_path.value().c_str(), st.st_mode); - } -#endif - - full_path_ = new_path; - - // We don't need to re-open the file if we're done (finished or canceled). - if (!saved_in_progress) - return true; - - if (!Open()) - return false; - - return true; -} - -void BaseFile::Detach() { - detached_ = true; -} - -void BaseFile::Cancel() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(!detached_); - - Close(); - - if (!full_path_.empty()) - file_util::Delete(full_path_, false); -} - -void BaseFile::Finish() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - if (calculate_hash_) - secure_hash_->Finish(sha256_hash_, kSha256HashLen); - - Close(); -} - -bool BaseFile::GetSha256Hash(std::string* hash) { - DCHECK(!detached_); - if (!calculate_hash_ || in_progress()) - return false; - hash->assign(reinterpret_cast<const char*>(sha256_hash_), - sizeof(sha256_hash_)); - return true; -} - -void BaseFile::AnnotateWithSourceInformation() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(!detached_); - -#if defined(OS_WIN) - // Sets the Zone to tell Windows that this file comes from the internet. - // We ignore the return value because a failure is not fatal. - win_util::SetInternetZoneIdentifier(full_path_, - UTF8ToWide(source_url_.spec())); -#elif defined(OS_MACOSX) - file_metadata::AddQuarantineMetadataToFile(full_path_, source_url_, - referrer_url_); - file_metadata::AddOriginMetadataToFile(full_path_, source_url_, - referrer_url_); -#endif -} - -bool BaseFile::Open() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(!detached_); - DCHECK(!full_path_.empty()); - - // Create a new file stream 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; - } - - // We may be re-opening the file after rename. Always make sure we're - // writing at the end of the file. - if (file_stream_->Seek(net::FROM_END, 0) < 0) { - file_stream_.reset(); - return false; - } - } - -#if defined(OS_WIN) - AnnotateWithSourceInformation(); -#endif - return true; -} - -void BaseFile::Close() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - if (file_stream_.get()) { -#if defined(OS_CHROMEOS) - // Currently we don't really care about the return value, since if it fails - // theres not much we can do. But we might in the future. - file_stream_->Flush(); -#endif - file_stream_->Close(); - file_stream_.reset(); - } -} - -std::string BaseFile::DebugString() const { - return base::StringPrintf("{ source_url_ = \"%s\"" - " full_path_ = \"%" PRFilePath "\"" - " bytes_so_far_ = %" PRId64 " detached_ = %c }", - source_url_.spec().c_str(), - full_path_.value().c_str(), - bytes_so_far_, - detached_ ? 'T' : 'F'); -} diff --git a/chrome/browser/download/base_file.h b/chrome/browser/download/base_file.h deleted file mode 100644 index 02563b7..0000000 --- a/chrome/browser/download/base_file.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_DOWNLOAD_BASE_FILE_H_ -#define CHROME_BROWSER_DOWNLOAD_BASE_FILE_H_ -#pragma once - -#include <string> - -#include "base/file_path.h" -#include "base/memory/linked_ptr.h" -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/power_save_blocker.h" -#include "googleurl/src/gurl.h" - -namespace crypto { -class SecureHash; -} -namespace net { -class FileStream; -} - -// File being downloaded and saved to disk. This is a base class -// for DownloadFile and SaveFile, which keep more state information. -class BaseFile { - public: - BaseFile(const FilePath& full_path, - const GURL& source_url, - const GURL& referrer_url, - int64 received_bytes, - const linked_ptr<net::FileStream>& file_stream); - virtual ~BaseFile(); - - // If calculate_hash is true, sha256 hash will be calculated. - bool Initialize(bool calculate_hash); - - // Write a new chunk of data to the file. Returns true on success (all bytes - // written to the file). - bool AppendDataToFile(const char* data, size_t data_len); - - // Rename the download file. Returns true on success. - virtual bool Rename(const FilePath& full_path); - - // Detach the file so it is not deleted on destruction. - virtual void Detach(); - - // Abort the download and automatically close the file. - void Cancel(); - - // Indicate that the download has finished. No new data will be received. - void Finish(); - - // Informs the OS that this file came from the internet. - void AnnotateWithSourceInformation(); - - FilePath full_path() const { return full_path_; } - bool in_progress() const { return file_stream_ != NULL; } - int64 bytes_so_far() const { return bytes_so_far_; } - - // Set |hash| with sha256 digest for the file. - // Returns true if digest is successfully calculated. - virtual bool GetSha256Hash(std::string* hash); - - virtual std::string DebugString() const; - - protected: - bool Open(); - void Close(); - - // Full path to the file including the file name. - FilePath full_path_; - - private: - static const size_t kSha256HashLen = 32; - - // Source URL for the file being downloaded. - GURL source_url_; - - // The URL where the download was initiated. - GURL referrer_url_; - - // OS file stream for writing - linked_ptr<net::FileStream> file_stream_; - - // Amount of data received up so far, in bytes. - int64 bytes_so_far_; - - // RAII handle to keep the system from sleeping while we're downloading. - PowerSaveBlocker power_save_blocker_; - - // Indicates if sha256 hash should be calculated for the file. - bool calculate_hash_; - - // Used to calculate sha256 hash for the file when calculate_hash_ - // is set. - scoped_ptr<crypto::SecureHash> secure_hash_; - - unsigned char sha256_hash_[kSha256HashLen]; - - // Indicates that this class no longer owns the associated file, and so - // won't delete it on destruction. - bool detached_; - - DISALLOW_COPY_AND_ASSIGN(BaseFile); -}; - -#endif // CHROME_BROWSER_DOWNLOAD_BASE_FILE_H_ diff --git a/chrome/browser/download/base_file_unittest.cc b/chrome/browser/download/base_file_unittest.cc deleted file mode 100644 index f8da90b..0000000 --- a/chrome/browser/download/base_file_unittest.cc +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" -#include "base/message_loop.h" -#include "base/scoped_temp_dir.h" -#include "base/string_number_conversions.h" -#include "chrome/browser/download/base_file.h" -#include "content/browser/browser_thread.h" -#include "net/base/file_stream.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const char kTestData1[] = "Let's write some data to the file!\n"; -const char kTestData2[] = "Writing more data.\n"; -const char kTestData3[] = "Final line."; - -class BaseFileTest : public testing::Test { - public: - BaseFileTest() - : expect_file_survives_(false), - file_thread_(BrowserThread::FILE, &message_loop_) { - } - - virtual void SetUp() { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - base_file_.reset( - new BaseFile(FilePath(), GURL(), GURL(), 0, file_stream_)); - } - - virtual void TearDown() { - EXPECT_FALSE(base_file_->in_progress()); - EXPECT_EQ(static_cast<int64>(expected_data_.size()), - base_file_->bytes_so_far()); - - FilePath full_path = base_file_->full_path(); - - if (!expected_data_.empty()) { - // Make sure the data has been properly written to disk. - std::string disk_data; - EXPECT_TRUE(file_util::ReadFileToString(full_path, &disk_data)); - EXPECT_EQ(expected_data_, disk_data); - } - - // Make sure the mock BrowserThread outlives the BaseFile to satisfy - // thread checks inside it. - base_file_.reset(); - - EXPECT_EQ(expect_file_survives_, file_util::PathExists(full_path)); - } - - void AppendDataToFile(const std::string& data) { - ASSERT_TRUE(base_file_->in_progress()); - base_file_->AppendDataToFile(data.data(), data.size()); - expected_data_ += data; - EXPECT_EQ(static_cast<int64>(expected_data_.size()), - base_file_->bytes_so_far()); - } - - protected: - linked_ptr<net::FileStream> file_stream_; - - // BaseClass instance we are testing. - scoped_ptr<BaseFile> base_file_; - - // Temporary directory for renamed downloads. - ScopedTempDir temp_dir_; - - // Expect the file to survive deletion of the BaseFile instance. - bool expect_file_survives_; - - private: - // Keep track of what data should be saved to the disk file. - std::string expected_data_; - - // Mock file thread to satisfy debug checks in BaseFile. - MessageLoop message_loop_; - BrowserThread file_thread_; -}; - -// Test the most basic scenario: just create the object and do a sanity check -// on all its accessors. This is actually a case that rarely happens -// in production, where we would at least Initialize it. -TEST_F(BaseFileTest, CreateDestroy) { - EXPECT_EQ(FilePath().value(), base_file_->full_path().value()); -} - -// Cancel the download explicitly. -TEST_F(BaseFileTest, Cancel) { - ASSERT_TRUE(base_file_->Initialize(false)); - EXPECT_TRUE(file_util::PathExists(base_file_->full_path())); - base_file_->Cancel(); - EXPECT_FALSE(file_util::PathExists(base_file_->full_path())); - EXPECT_NE(FilePath().value(), base_file_->full_path().value()); -} - -// Write data to the file and detach it, so it doesn't get deleted -// automatically when base_file_ is destructed. -TEST_F(BaseFileTest, WriteAndDetach) { - ASSERT_TRUE(base_file_->Initialize(false)); - AppendDataToFile(kTestData1); - base_file_->Finish(); - base_file_->Detach(); - expect_file_survives_ = true; -} - -// Write data to the file and detach it, and calculate its sha256 hash. -TEST_F(BaseFileTest, WriteWithHashAndDetach) { - ASSERT_TRUE(base_file_->Initialize(true)); - AppendDataToFile(kTestData1); - base_file_->Finish(); - - std::string hash; - base_file_->GetSha256Hash(&hash); - EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE", - base::HexEncode(hash.data(), hash.size())); - - base_file_->Detach(); - expect_file_survives_ = true; -} - -// Rename the file after writing to it, then detach. -TEST_F(BaseFileTest, WriteThenRenameAndDetach) { - ASSERT_TRUE(base_file_->Initialize(false)); - - FilePath initial_path(base_file_->full_path()); - EXPECT_TRUE(file_util::PathExists(initial_path)); - FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); - EXPECT_FALSE(file_util::PathExists(new_path)); - - AppendDataToFile(kTestData1); - - EXPECT_TRUE(base_file_->Rename(new_path)); - EXPECT_FALSE(file_util::PathExists(initial_path)); - EXPECT_TRUE(file_util::PathExists(new_path)); - - base_file_->Finish(); - base_file_->Detach(); - expect_file_survives_ = true; -} - -// Write data to the file once. -TEST_F(BaseFileTest, SingleWrite) { - ASSERT_TRUE(base_file_->Initialize(false)); - AppendDataToFile(kTestData1); - base_file_->Finish(); -} - -// Write data to the file multiple times. -TEST_F(BaseFileTest, MultipleWrites) { - ASSERT_TRUE(base_file_->Initialize(false)); - AppendDataToFile(kTestData1); - AppendDataToFile(kTestData2); - AppendDataToFile(kTestData3); - std::string hash; - EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); - base_file_->Finish(); -} - -// Write data to the file once and calculate its sha256 hash. -TEST_F(BaseFileTest, SingleWriteWithHash) { - ASSERT_TRUE(base_file_->Initialize(true)); - AppendDataToFile(kTestData1); - base_file_->Finish(); - - std::string hash; - base_file_->GetSha256Hash(&hash); - EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE", - base::HexEncode(hash.data(), hash.size())); -} - -// Write data to the file multiple times and calculate its sha256 hash. -TEST_F(BaseFileTest, MultipleWritesWithHash) { - std::string hash; - - ASSERT_TRUE(base_file_->Initialize(true)); - AppendDataToFile(kTestData1); - AppendDataToFile(kTestData2); - AppendDataToFile(kTestData3); - // no hash before Finish() is called either. - EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); - base_file_->Finish(); - - EXPECT_TRUE(base_file_->GetSha256Hash(&hash)); - EXPECT_EQ("CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8", - base::HexEncode(hash.data(), hash.size())); -} - -// Rename the file after all writes to it. -TEST_F(BaseFileTest, WriteThenRename) { - ASSERT_TRUE(base_file_->Initialize(false)); - - FilePath initial_path(base_file_->full_path()); - EXPECT_TRUE(file_util::PathExists(initial_path)); - FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); - EXPECT_FALSE(file_util::PathExists(new_path)); - - AppendDataToFile(kTestData1); - - EXPECT_TRUE(base_file_->Rename(new_path)); - EXPECT_FALSE(file_util::PathExists(initial_path)); - EXPECT_TRUE(file_util::PathExists(new_path)); - - base_file_->Finish(); -} - -// Rename the file while the download is still in progress. -TEST_F(BaseFileTest, RenameWhileInProgress) { - ASSERT_TRUE(base_file_->Initialize(false)); - - FilePath initial_path(base_file_->full_path()); - EXPECT_TRUE(file_util::PathExists(initial_path)); - FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); - EXPECT_FALSE(file_util::PathExists(new_path)); - - AppendDataToFile(kTestData1); - - EXPECT_TRUE(base_file_->in_progress()); - EXPECT_TRUE(base_file_->Rename(new_path)); - EXPECT_FALSE(file_util::PathExists(initial_path)); - EXPECT_TRUE(file_util::PathExists(new_path)); - - AppendDataToFile(kTestData2); - - base_file_->Finish(); -} - -} // namespace diff --git a/chrome/browser/download/download_file.h b/chrome/browser/download/download_file.h index 4fa3bfc..b94f9aa 100644 --- a/chrome/browser/download/download_file.h +++ b/chrome/browser/download/download_file.h @@ -10,9 +10,9 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" -#include "chrome/browser/download/base_file.h" #include "chrome/browser/download/download_request_handle.h" #include "chrome/browser/download/download_types.h" +#include "content/browser/download/base_file.h" struct DownloadCreateInfo; class DownloadManager; diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc index f37cb1f..5c8e793 100644 --- a/chrome/browser/download/download_item_model.cc +++ b/chrome/browser/download/download_item_model.cc @@ -9,8 +9,8 @@ #include "base/string16.h" #include "base/utf_string_conversions.h" #include "chrome/browser/download/download_item.h" -#include "chrome/browser/download/save_package.h" #include "chrome/common/time_format.h" +#include "content/browser/download/save_package.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/text/bytes_formatting.h" diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc index e9e0b76..01202d8 100644 --- a/chrome/browser/download/download_prefs.cc +++ b/chrome/browser/download/download_prefs.cc @@ -12,10 +12,10 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/download/download_extensions.h" #include "chrome/browser/download/download_util.h" -#include "chrome/browser/download/save_package.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/common/pref_names.h" #include "content/browser/browser_thread.h" +#include "content/browser/download/save_package.h" DownloadPrefs::DownloadPrefs(PrefService* prefs) : prefs_(prefs) { prompt_for_download_.Init(prefs::kPromptForDownload, prefs, NULL); diff --git a/chrome/browser/download/save_file.cc b/chrome/browser/download/save_file.cc deleted file mode 100644 index 4c53c2d..0000000 --- a/chrome/browser/download/save_file.cc +++ /dev/null @@ -1,22 +0,0 @@ -// 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/save_file.h" - -#include "base/logging.h" -#include "content/browser/browser_thread.h" -#include "net/base/file_stream.h" - -SaveFile::SaveFile(const SaveFileCreateInfo* info) - : BaseFile(FilePath(), info->url, GURL(), 0, linked_ptr<net::FileStream>()), - info_(info) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - DCHECK(info); - DCHECK(info->path.empty()); -} - -SaveFile::~SaveFile() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); -} diff --git a/chrome/browser/download/save_file.h b/chrome/browser/download/save_file.h deleted file mode 100644 index fc610f7..0000000 --- a/chrome/browser/download/save_file.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H_ -#define CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H_ -#pragma once - -#include "base/basictypes.h" -#include "base/file_path.h" -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/download/base_file.h" -#include "chrome/browser/download/save_types.h" - -// SaveFile ---------------------------------------------------------------- - -// These objects live exclusively on the file thread and handle the writing -// operations for one save item. These objects live only for the duration that -// the saving job is 'in progress': once the saving job has been completed or -// canceled, the SaveFile is destroyed. One SaveFile object represents one item -// in a save session. -class SaveFile : public BaseFile { - public: - explicit SaveFile(const SaveFileCreateInfo* info); - virtual ~SaveFile(); - - // Accessors. - int save_id() const { return info_->save_id; } - int render_process_id() const { return info_->render_process_id; } - int render_view_id() const { return info_->render_view_id; } - int request_id() const { return info_->request_id; } - SaveFileCreateInfo::SaveFileSource save_source() const { - return info_->save_source; - } - - private: - scoped_ptr<const SaveFileCreateInfo> info_; - - DISALLOW_COPY_AND_ASSIGN(SaveFile); -}; - -#endif // CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H_ diff --git a/chrome/browser/download/save_file_manager.cc b/chrome/browser/download/save_file_manager.cc deleted file mode 100644 index d5df502..0000000 --- a/chrome/browser/download/save_file_manager.cc +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" - -#include "chrome/browser/download/save_file_manager.h" - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/stl_util-inl.h" -#include "base/string_util.h" -#include "base/task.h" -#include "base/threading/thread.h" -#include "chrome/browser/download/save_file.h" -#include "chrome/browser/download/save_package.h" -#include "chrome/browser/platform_util.h" -#include "chrome/browser/tab_contents/tab_util.h" -#include "chrome/browser/ui/download/download_tab_helper.h" -#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" -#include "chrome/common/chrome_paths.h" -#include "content/browser/browser_thread.h" -#include "content/browser/renderer_host/resource_dispatcher_host.h" -#include "content/browser/tab_contents/tab_contents.h" -#include "googleurl/src/gurl.h" -#include "net/base/net_util.h" -#include "net/base/io_buffer.h" - -SaveFileManager::SaveFileManager(ResourceDispatcherHost* rdh) - : next_id_(0), - resource_dispatcher_host_(rdh) { - DCHECK(resource_dispatcher_host_); -} - -SaveFileManager::~SaveFileManager() { - // Check for clean shutdown. - DCHECK(save_file_map_.empty()); -} - -// Called during the browser shutdown process to clean up any state (open files, -// timers) that live on the saving thread (file thread). -void SaveFileManager::Shutdown() { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(this, &SaveFileManager::OnShutdown)); -} - -// Stop file thread operations. -void SaveFileManager::OnShutdown() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - STLDeleteValues(&save_file_map_); -} - -SaveFile* SaveFileManager::LookupSaveFile(int save_id) { - SaveFileMap::iterator it = save_file_map_.find(save_id); - return it == save_file_map_.end() ? NULL : it->second; -} - -// Called on the IO thread when -// a) The ResourceDispatcherHost has decided that a request is savable. -// b) The resource does not come from the network, but we still need a -// save ID for for managing the status of the saving operation. So we -// file a request from the file thread to the IO thread to generate a -// unique save ID. -int SaveFileManager::GetNextId() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - return next_id_++; -} - -void SaveFileManager::RegisterStartingRequest(const GURL& save_url, - SavePackage* save_package) { - // Make sure it runs in the UI thread. - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - int tab_id = save_package->tab_id(); - - // Register this starting request. - StartingRequestsMap& starting_requests = tab_starting_requests_[tab_id]; - bool never_present = starting_requests.insert( - StartingRequestsMap::value_type(save_url.spec(), save_package)).second; - DCHECK(never_present); -} - -SavePackage* SaveFileManager::UnregisterStartingRequest( - const GURL& save_url, int tab_id) { - // Make sure it runs in UI thread. - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - TabToStartingRequestsMap::iterator it = tab_starting_requests_.find(tab_id); - if (it != tab_starting_requests_.end()) { - StartingRequestsMap& requests = it->second; - StartingRequestsMap::iterator sit = requests.find(save_url.spec()); - if (sit == requests.end()) - return NULL; - - // Found, erase it from starting list and return SavePackage. - SavePackage* save_package = sit->second; - requests.erase(sit); - // If there is no element in requests, remove it - if (requests.empty()) - tab_starting_requests_.erase(it); - return save_package; - } - - return NULL; -} - -// Look up a SavePackage according to a save id. -SavePackage* SaveFileManager::LookupPackage(int save_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - SavePackageMap::iterator it = packages_.find(save_id); - if (it != packages_.end()) - return it->second; - return NULL; -} - -// Call from SavePackage for starting a saving job -void SaveFileManager::SaveURL( - const GURL& url, - const GURL& referrer, - int render_process_host_id, - int render_view_id, - SaveFileCreateInfo::SaveFileSource save_source, - const FilePath& file_full_path, - const content::ResourceContext& context, - SavePackage* save_package) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // Register a saving job. - RegisterStartingRequest(url, save_package); - if (save_source == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { - DCHECK(url.is_valid()); - - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableMethod(this, - &SaveFileManager::OnSaveURL, - url, - referrer, - render_process_host_id, - render_view_id, - &context)); - } else { - // We manually start the save job. - SaveFileCreateInfo* info = new SaveFileCreateInfo(file_full_path, - url, - save_source, - -1); - info->render_process_id = render_process_host_id; - info->render_view_id = render_view_id; - - // Since the data will come from render process, so we need to start - // this kind of save job by ourself. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableMethod( - this, &SaveFileManager::OnRequireSaveJobFromOtherSource, info)); - } -} - -// Utility function for look up table maintenance, called on the UI thread. -// A manager may have multiple save page job (SavePackage) in progress, -// so we just look up the save id and remove it from the tracking table. -// If the save id is -1, it means we just send a request to save, but the -// saving action has still not happened, need to call UnregisterStartingRequest -// to remove it from the tracking map. -void SaveFileManager::RemoveSaveFile(int save_id, const GURL& save_url, - SavePackage* package) { - DCHECK(package); - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // A save page job (SavePackage) can only have one manager, - // so remove it if it exists. - if (save_id == -1) { - SavePackage* old_package = UnregisterStartingRequest(save_url, - package->tab_id()); - DCHECK_EQ(old_package, package); - } else { - SavePackageMap::iterator it = packages_.find(save_id); - if (it != packages_.end()) - packages_.erase(it); - } -} - -// Static -// Utility function for converting request IDs to a TabContents. Must be called -// only on the UI thread. -SavePackage* SaveFileManager::GetSavePackageFromRenderIds( - int render_process_id, int render_view_id) { - TabContents* contents = tab_util::GetTabContentsByID(render_process_id, - render_view_id); - if (contents) { - TabContentsWrapper* wrapper = - TabContentsWrapper::GetCurrentWrapperForContents(contents); - return wrapper->download_tab_helper()->save_package(); - } - - return NULL; -} - -// Utility function for deleting specified file. -void SaveFileManager::DeleteDirectoryOrFile(const FilePath& full_path, - bool is_dir) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - this, &SaveFileManager::OnDeleteDirectoryOrFile, full_path, is_dir)); -} - -void SaveFileManager::SendCancelRequest(int save_id) { - // Cancel the request which has specific save id. - DCHECK_GT(save_id, -1); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(this, &SaveFileManager::CancelSave, save_id)); -} - -// Notifications sent from the IO thread and run on the file thread: - -// The IO thread created |info|, but the file thread (this method) uses it -// to create a SaveFile which will hold and finally destroy |info|. It will -// then passes |info| to the UI thread for reporting saving status. -void SaveFileManager::StartSave(SaveFileCreateInfo* info) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(info); - SaveFile* save_file = new SaveFile(info); - - // TODO(phajdan.jr): We should check the return value and handle errors here. - save_file->Initialize(false); // No need to calculate hash. - - DCHECK(!LookupSaveFile(info->save_id)); - save_file_map_[info->save_id] = save_file; - info->path = save_file->full_path(); - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod(this, &SaveFileManager::OnStartSave, info)); -} - -// We do forward an update to the UI thread here, since we do not use timer to -// update the UI. If the user has canceled the saving action (in the UI -// thread). We may receive a few more updates before the IO thread gets the -// cancel message. We just delete the data since the SaveFile has been deleted. -void SaveFileManager::UpdateSaveProgress(int save_id, - net::IOBuffer* data, - int data_len) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - SaveFile* save_file = LookupSaveFile(save_id); - if (save_file) { - bool write_success = save_file->AppendDataToFile(data->data(), data_len); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - this, &SaveFileManager::OnUpdateSaveProgress, save_file->save_id(), - save_file->bytes_so_far(), write_success)); - } -} - -// The IO thread will call this when saving is completed or it got error when -// fetching data. In the former case, we forward the message to OnSaveFinished -// in UI thread. In the latter case, the save ID will be -1, which means the -// saving action did not even start, so we need to call OnErrorFinished in UI -// thread, which will use the save URL to find corresponding request record and -// delete it. -void SaveFileManager::SaveFinished(int save_id, - const GURL& save_url, - int render_process_id, - bool is_success) { - VLOG(20) << " " << __FUNCTION__ << "()" - << " save_id = " << save_id - << " save_url = \"" << save_url.spec() << "\"" - << " is_success = " << is_success; - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - SaveFileMap::iterator it = save_file_map_.find(save_id); - if (it != save_file_map_.end()) { - SaveFile* save_file = it->second; - VLOG(20) << " " << __FUNCTION__ << "()" - << " save_file = " << save_file->DebugString(); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - this, &SaveFileManager::OnSaveFinished, save_id, - save_file->bytes_so_far(), is_success)); - - save_file->Finish(); - save_file->Detach(); - } else if (save_id == -1) { - // Before saving started, we got error. We still call finish process. - DCHECK(!save_url.is_empty()); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - this, &SaveFileManager::OnErrorFinished, save_url, - render_process_id)); - } -} - -// Notifications sent from the file thread and run on the UI thread. - -void SaveFileManager::OnStartSave(const SaveFileCreateInfo* info) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - SavePackage* save_package = - GetSavePackageFromRenderIds(info->render_process_id, - info->render_view_id); - if (!save_package) { - // Cancel this request. - SendCancelRequest(info->save_id); - return; - } - - // Insert started saving job to tracking list. - SavePackageMap::iterator sit = packages_.find(info->save_id); - if (sit == packages_.end()) { - // Find the registered request. If we can not find, it means we have - // canceled the job before. - SavePackage* old_save_package = UnregisterStartingRequest(info->url, - info->render_process_id); - if (!old_save_package) { - // Cancel this request. - SendCancelRequest(info->save_id); - return; - } - DCHECK_EQ(old_save_package, save_package); - packages_[info->save_id] = save_package; - } else { - NOTREACHED(); - } - - // Forward this message to SavePackage. - save_package->StartSave(info); -} - -void SaveFileManager::OnUpdateSaveProgress(int save_id, int64 bytes_so_far, - bool write_success) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - SavePackage* package = LookupPackage(save_id); - if (package) - package->UpdateSaveProgress(save_id, bytes_so_far, write_success); - else - SendCancelRequest(save_id); -} - -void SaveFileManager::OnSaveFinished(int save_id, - int64 bytes_so_far, - bool is_success) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - SavePackage* package = LookupPackage(save_id); - if (package) - package->SaveFinished(save_id, bytes_so_far, is_success); -} - -void SaveFileManager::OnErrorFinished(const GURL& save_url, int tab_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - SavePackage* save_package = UnregisterStartingRequest(save_url, tab_id); - if (save_package) - save_package->SaveFailed(save_url); -} - -// Notifications sent from the UI thread and run on the IO thread. - -void SaveFileManager::OnSaveURL( - const GURL& url, - const GURL& referrer, - int render_process_host_id, - int render_view_id, - const content::ResourceContext* context) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - resource_dispatcher_host_->BeginSaveFile(url, - referrer, - render_process_host_id, - render_view_id, - *context); -} - -void SaveFileManager::OnRequireSaveJobFromOtherSource( - SaveFileCreateInfo* info) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DCHECK_EQ(info->save_id, -1); - // Generate a unique save id. - info->save_id = GetNextId(); - // Start real saving action. - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(this, &SaveFileManager::StartSave, info)); -} - -void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id, - int request_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - resource_dispatcher_host_->CancelRequest(render_process_id, - request_id, - false); -} - -// Notifications sent from the UI thread and run on the file thread. - -// This method will be sent via a user action, or shutdown on the UI thread, -// and run on the file thread. We don't post a message back for cancels, -// but we do forward the cancel to the IO thread. Since this message has been -// sent from the UI thread, the saving job may have already completed and -// won't exist in our map. -void SaveFileManager::CancelSave(int save_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - SaveFileMap::iterator it = save_file_map_.find(save_id); - if (it != save_file_map_.end()) { - SaveFile* save_file = it->second; - - // If the data comes from the net IO thread, then forward the cancel - // message to IO thread. If the data comes from other sources, just - // ignore the cancel message. - if (save_file->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableMethod( - this, &SaveFileManager::ExecuteCancelSaveRequest, - save_file->render_process_id(), save_file->request_id())); - - // UI thread will notify the render process to stop sending data, - // so in here, we need not to do anything, just close the save file. - save_file->Cancel(); - } else { - // If we did not find SaveFile in map, the saving job should either get - // data from other sources or have finished. - DCHECK(save_file->save_source() != - SaveFileCreateInfo::SAVE_FILE_FROM_NET || - !save_file->in_progress()); - } - // Whatever the save file is renamed or not, just delete it. - save_file_map_.erase(it); - delete save_file; - } -} - -// It is possible that SaveItem which has specified save_id has been canceled -// before this function runs. So if we can not find corresponding SaveFile by -// using specified save_id, just return. -void SaveFileManager::SaveLocalFile(const GURL& original_file_url, - int save_id, - int render_process_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - SaveFile* save_file = LookupSaveFile(save_id); - if (!save_file) - return; - // If it has finished, just return. - if (!save_file->in_progress()) - return; - - // Close the save file before the copy operation. - save_file->Finish(); - save_file->Detach(); - - DCHECK(original_file_url.SchemeIsFile()); - FilePath file_path; - net::FileURLToFilePath(original_file_url, &file_path); - // If we can not get valid file path from original URL, treat it as - // disk error. - if (file_path.empty()) - SaveFinished(save_id, original_file_url, render_process_id, false); - - // Copy the local file to the temporary file. It will be renamed to its - // final name later. - bool success = file_util::CopyFile(file_path, save_file->full_path()); - if (!success) - file_util::Delete(save_file->full_path(), false); - SaveFinished(save_id, original_file_url, render_process_id, success); -} - -void SaveFileManager::OnDeleteDirectoryOrFile(const FilePath& full_path, - bool is_dir) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(!full_path.empty()); - - file_util::Delete(full_path, is_dir); -} - -// Open a saved page package, show it in a Windows Explorer window. -// We run on this thread to avoid blocking the UI with slow Shell operations. -#if !defined(OS_MACOSX) -void SaveFileManager::OnShowSavedFileInShell(const FilePath full_path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - platform_util::ShowItemInFolder(full_path); -} -#endif - -void SaveFileManager::RenameAllFiles( - const FinalNameList& final_names, - const FilePath& resource_dir, - int render_process_id, - int render_view_id, - int save_package_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - if (!resource_dir.empty() && !file_util::PathExists(resource_dir)) - file_util::CreateDirectory(resource_dir); - - for (FinalNameList::const_iterator i = final_names.begin(); - i != final_names.end(); ++i) { - SaveFileMap::iterator it = save_file_map_.find(i->first); - if (it != save_file_map_.end()) { - SaveFile* save_file = it->second; - DCHECK(!save_file->in_progress()); - save_file->Rename(i->second); - delete save_file; - save_file_map_.erase(it); - } - } - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - this, &SaveFileManager::OnFinishSavePageJob, render_process_id, - render_view_id, save_package_id)); -} - -void SaveFileManager::OnFinishSavePageJob(int render_process_id, - int render_view_id, - int save_package_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - SavePackage* save_package = - GetSavePackageFromRenderIds(render_process_id, render_view_id); - - if (save_package && save_package->id() == save_package_id) - save_package->Finish(); -} - -void SaveFileManager::RemoveSavedFileFromFileMap( - const SaveIDList& save_ids) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - for (SaveIDList::const_iterator i = save_ids.begin(); - i != save_ids.end(); ++i) { - SaveFileMap::iterator it = save_file_map_.find(*i); - if (it != save_file_map_.end()) { - SaveFile* save_file = it->second; - DCHECK(!save_file->in_progress()); - file_util::Delete(save_file->full_path(), false); - delete save_file; - save_file_map_.erase(it); - } - } -} diff --git a/chrome/browser/download/save_file_manager.h b/chrome/browser/download/save_file_manager.h deleted file mode 100644 index 60a831c..0000000 --- a/chrome/browser/download/save_file_manager.h +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Objects that handle file operations for saving files, on the file thread. -// -// The SaveFileManager owns a set of SaveFile objects, each of which connects -// with a SaveItem object which belongs to one SavePackage and runs on the file -// thread for saving data in order to avoid disk activity on either network IO -// thread or the UI thread. It coordinates the notifications from the network -// and UI. -// -// The SaveFileManager itself is a singleton object owned by the -// ResourceDispatcherHost. -// -// The data sent to SaveFileManager have 2 sources, one is from -// ResourceDispatcherHost, run in network IO thread, the all sub-resources -// and save-only-HTML pages will be got from network IO. The second is from -// render process, those html pages which are serialized from DOM will be -// composed in render process and encoded to its original encoding, then sent -// to UI loop in browser process, then UI loop will dispatch the data to -// SaveFileManager on the file thread. SaveFileManager will directly -// call SaveFile's method to persist data. -// -// A typical saving job operation involves multiple threads: -// -// Updating an in progress save file -// io_thread -// |----> data from net ---->| -// | -// | -// |----> data from ---->| | -// | render process | | -// ui_thread | | -// file_thread (writes to disk) -// |----> stats ---->| -// ui_thread (feedback for user) -// -// -// Cancel operations perform the inverse order when triggered by a user action: -// ui_thread (user click) -// |----> cancel command ---->| -// | | file_thread (close file) -// | |---------------------> cancel command ---->| -// | io_thread (stops net IO -// ui_thread (user close tab) for saving) -// |----> cancel command ---->| -// Render process(stop serializing DOM and sending -// data) -// -// -// The SaveFileManager tracks saving requests, mapping from a save ID -// (unique integer created in the IO thread) to the SavePackage for the -// tab where the saving job was initiated. In the event of a tab closure -// during saving, the SavePackage will notice the SaveFileManage to -// cancel all SaveFile job. - -#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ -#define CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ -#pragma once - -#include <string> - -#include "base/basictypes.h" -#include "base/hash_tables.h" -#include "base/memory/ref_counted.h" -#include "chrome/browser/download/save_types.h" - -class FilePath; -class GURL; -class SaveFile; -class SavePackage; -class ResourceDispatcherHost; -class Task; - -namespace content { -class ResourceContext; -} - -namespace net { -class IOBuffer; -} - -class SaveFileManager - : public base::RefCountedThreadSafe<SaveFileManager> { - public: - explicit SaveFileManager(ResourceDispatcherHost* rdh); - - // Lifetime management. - void Shutdown(); - - // Called on the IO thread - int GetNextId(); - - // Save the specified URL. Called on the UI thread and forwarded to the - // ResourceDispatcherHost on the IO thread. - void SaveURL(const GURL& url, - const GURL& referrer, - int render_process_host_id, - int render_view_id, - SaveFileCreateInfo::SaveFileSource save_source, - const FilePath& file_full_path, - const content::ResourceContext& context, - SavePackage* save_package); - - // Notifications sent from the IO thread and run on the file thread: - void StartSave(SaveFileCreateInfo* info); - void UpdateSaveProgress(int save_id, net::IOBuffer* data, int size); - void SaveFinished(int save_id, - const GURL& save_url, - int render_process_id, - bool is_success); - - // Notifications sent from the UI thread and run on the file thread. - // Cancel a SaveFile instance which has specified save id. - void CancelSave(int save_id); - - // Called on the UI thread to remove a save package from SaveFileManager's - // tracking map. - void RemoveSaveFile(int save_id, const GURL& save_url, - SavePackage* package); - -#if !defined(OS_MACOSX) - // Handler for shell operations sent from the UI to the file thread. Mac OS X - // requires opening downloads on the UI thread, so it does not use this - // method. - void OnShowSavedFileInShell(const FilePath full_path); -#endif - - // Helper function for deleting specified file. - void DeleteDirectoryOrFile(const FilePath& full_path, bool is_dir); - - // Runs on file thread to save a file by copying from file system when - // original url is using file scheme. - void SaveLocalFile(const GURL& original_file_url, - int save_id, - int render_process_id); - - // Renames all the successfully saved files. - // |final_names| points to a vector which contains pairs of save ids and - // final names of successfully saved files. - void RenameAllFiles( - const FinalNameList& final_names, - const FilePath& resource_dir, - int render_process_id, - int render_view_id, - int save_package_id); - - // When the user cancels the saving, we need to remove all remaining saved - // files of this page saving job from save_file_map_. - void RemoveSavedFileFromFileMap(const SaveIDList & save_ids); - - private: - friend class base::RefCountedThreadSafe<SaveFileManager>; - - ~SaveFileManager(); - - // A cleanup helper that runs on the file thread. - void OnShutdown(); - - // Called only on UI thread to get the SavePackage for a tab's profile. - static SavePackage* GetSavePackageFromRenderIds(int render_process_id, - int review_view_id); - - // Register a starting request. Associate the save URL with a - // SavePackage for further matching. - void RegisterStartingRequest(const GURL& save_url, - SavePackage* save_package); - // Unregister a start request according save URL, disassociate - // the save URL and SavePackage. - SavePackage* UnregisterStartingRequest(const GURL& save_url, - int tab_id); - - // Look up the SavePackage according to save id. - SavePackage* LookupPackage(int save_id); - - // Called only on the file thread. - // Look up one in-progress saving item according to save id. - SaveFile* LookupSaveFile(int save_id); - - // Help function for sending notification of canceling specific request. - void SendCancelRequest(int save_id); - - // Notifications sent from the file thread and run on the UI thread. - - // Lookup the SaveManager for this TabContents' saving profile and inform it - // the saving job has been started. - void OnStartSave(const SaveFileCreateInfo* info); - // Update the SavePackage with the current state of a started saving job. - // If the SavePackage for this saving job is gone, cancel the request. - void OnUpdateSaveProgress(int save_id, - int64 bytes_so_far, - bool write_success); - // Update the SavePackage with the finish state, and remove the request - // tracking entries. - void OnSaveFinished(int save_id, int64 bytes_so_far, bool is_success); - // For those requests that do not have valid save id, use - // map:(url, SavePackage) to find the request and remove it. - void OnErrorFinished(const GURL& save_url, int tab_id); - // Notifies SavePackage that the whole page saving job is finished. - void OnFinishSavePageJob(int render_process_id, - int render_view_id, - int save_package_id); - - // Notifications sent from the UI thread and run on the file thread. - - // Deletes a specified file on the file thread. - void OnDeleteDirectoryOrFile(const FilePath& full_path, bool is_dir); - - // Notifications sent from the UI thread and run on the IO thread - - // Initiates a request for URL to be saved. - void OnSaveURL(const GURL& url, - const GURL& referrer, - int render_process_host_id, - int render_view_id, - const content::ResourceContext* context); - // Handler for a notification sent to the IO thread for generating save id. - void OnRequireSaveJobFromOtherSource(SaveFileCreateInfo* info); - // Call ResourceDispatcherHost's CancelRequest method to execute cancel - // action in the IO thread. - void ExecuteCancelSaveRequest(int render_process_id, int request_id); - - // Unique ID for the next SaveFile object. - int next_id_; - - // A map of all saving jobs by using save id. - typedef base::hash_map<int, SaveFile*> SaveFileMap; - SaveFileMap save_file_map_; - - ResourceDispatcherHost* resource_dispatcher_host_; - - // Tracks which SavePackage to send data to, called only on UI thread. - // SavePackageMap maps save IDs to their SavePackage. - typedef base::hash_map<int, SavePackage*> SavePackageMap; - SavePackageMap packages_; - - // There is a gap between after calling SaveURL() and before calling - // StartSave(). In this gap, each request does not have save id for tracking. - // But sometimes users might want to stop saving job or ResourceDispatcherHost - // calls SaveFinished with save id -1 for network error. We name the requests - // as starting requests. For tracking those starting requests, we need to - // have some data structure. - // First we use a hashmap to map the request URL to SavePackage, then we - // use a hashmap to map the tab id (we actually use render_process_id) to the - // hashmap since it is possible to save same URL in different tab at - // same time. - typedef base::hash_map<std::string, SavePackage*> StartingRequestsMap; - typedef base::hash_map<int, StartingRequestsMap> TabToStartingRequestsMap; - TabToStartingRequestsMap tab_starting_requests_; - - DISALLOW_COPY_AND_ASSIGN(SaveFileManager); -}; - -#endif // CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ diff --git a/chrome/browser/download/save_item.cc b/chrome/browser/download/save_item.cc deleted file mode 100644 index adb60b3..0000000 --- a/chrome/browser/download/save_item.cc +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/download/save_item.h" - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/string_util.h" -#include "chrome/browser/download/save_file.h" -#include "chrome/browser/download/save_file_manager.h" -#include "chrome/browser/download/save_package.h" - -// Constructor for SaveItem when creating each saving job. -SaveItem::SaveItem(const GURL& url, - const GURL& referrer, - SavePackage* package, - SaveFileCreateInfo::SaveFileSource save_source) - : save_id_(-1), - url_(url), - referrer_(referrer), - total_bytes_(0), - received_bytes_(0), - state_(WAIT_START), - has_final_name_(false), - is_success_(false), - save_source_(save_source), - package_(package) { - DCHECK(package); -} - -SaveItem::~SaveItem() { -} - -// Set start state for save item. -void SaveItem::Start() { - DCHECK(state_ == WAIT_START); - state_ = IN_PROGRESS; -} - -// If we've received more data than we were expecting (bad server info?), -// revert to 'unknown size mode'. -void SaveItem::UpdateSize(int64 bytes_so_far) { - received_bytes_ = bytes_so_far; - if (received_bytes_ >= total_bytes_) - total_bytes_ = 0; -} - -// Updates from the file thread may have been posted while this saving job -// was being canceled in the UI thread, so we'll accept them unless we're -// complete. -void SaveItem::Update(int64 bytes_so_far) { - if (state_ != IN_PROGRESS) { - NOTREACHED(); - return; - } - UpdateSize(bytes_so_far); -} - -// Cancel this saving item job. If the job is not in progress, ignore -// this command. The SavePackage will each in-progress SaveItem's cancel -// when canceling whole saving page job. -void SaveItem::Cancel() { - // If item is in WAIT_START mode, which means no request has been sent. - // So we need not to cancel it. - if (state_ != IN_PROGRESS) { - // Small downloads might be complete before method has a chance to run. - return; - } - state_ = CANCELED; - is_success_ = false; - Finish(received_bytes_, false); - package_->SaveCanceled(this); -} - -// Set finish state for a save item -void SaveItem::Finish(int64 size, bool is_success) { - // When this function is called, the SaveItem should be one of following - // three situations. - // a) The data of this SaveItem is finished saving. So it should have - // generated final name. - // b) Error happened before the start of saving process. So no |save_id_| is - // generated for this SaveItem and the |is_success_| should be false. - // c) Error happened in the start of saving process, the SaveItem has a save - // id, |is_success_| should be false, and the |size| should be 0. - DCHECK(has_final_name() || (save_id_ == -1 && !is_success_) || - (save_id_ != -1 && !is_success_ && !size)); - state_ = COMPLETE; - is_success_ = is_success; - UpdateSize(size); -} - -// Calculate the percentage of the save item -int SaveItem::PercentComplete() const { - switch (state_) { - case COMPLETE: - case CANCELED: - return 100; - case WAIT_START: - return 0; - case IN_PROGRESS: { - int percent = 0; - if (total_bytes_ > 0) - percent = static_cast<int>(received_bytes_ * 100.0 / total_bytes_); - return percent; - } - default: { - NOTREACHED(); - return -1; - } - } -} - -// Rename the save item with new path. -void SaveItem::Rename(const FilePath& full_path) { - DCHECK(!full_path.empty() && !has_final_name()); - full_path_ = full_path; - file_name_ = full_path_.BaseName(); - has_final_name_ = true; -} - -void SaveItem::SetSaveId(int32 save_id) { - DCHECK(save_id_ == -1); - save_id_ = save_id; -} - -void SaveItem::SetTotalBytes(int64 total_bytes) { - DCHECK(total_bytes_ == 0); - total_bytes_ = total_bytes; -} diff --git a/chrome/browser/download/save_item.h b/chrome/browser/download/save_item.h deleted file mode 100644 index 724441a..0000000 --- a/chrome/browser/download/save_item.h +++ /dev/null @@ -1,112 +0,0 @@ -// 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_SAVE_ITEM_H__ -#define CHROME_BROWSER_DOWNLOAD_SAVE_ITEM_H__ -#pragma once - -#include "base/basictypes.h" -#include "base/file_path.h" -#include "chrome/browser/download/save_types.h" -#include "googleurl/src/gurl.h" - -class SavePackage; - -// One SaveItem per save file. This is the model class that stores all the -// state for one save file. -class SaveItem { - public: - enum SaveState { - WAIT_START, - IN_PROGRESS, - COMPLETE, - CANCELED - }; - - SaveItem(const GURL& url, - const GURL& referrer, - SavePackage* package, - SaveFileCreateInfo::SaveFileSource save_source); - - ~SaveItem(); - - void Start(); - - // Received a new chunk of data. - void Update(int64 bytes_so_far); - - // Cancel saving item. - void Cancel(); - - // Saving operation completed. - void Finish(int64 size, bool is_success); - - // Rough percent complete, -1 means we don't know (since we didn't receive a - // total size). - int PercentComplete() const; - - // Update path for SaveItem, the actual file is renamed on the file thread. - void Rename(const FilePath& full_path); - - void SetSaveId(int32 save_id); - - void SetTotalBytes(int64 total_bytes); - - // Accessors. - SaveState state() const { return state_; } - const FilePath& full_path() const { return full_path_; } - const FilePath& file_name() const { return file_name_; } - const GURL& url() const { return url_; } - const GURL& referrer() const { return referrer_; } - int64 total_bytes() const { return total_bytes_; } - int64 received_bytes() const { return received_bytes_; } - int32 save_id() const { return save_id_; } - bool has_final_name() const { return has_final_name_; } - bool success() const { return is_success_; } - SaveFileCreateInfo::SaveFileSource save_source() const { - return save_source_; - } - SavePackage* package() const { return package_; } - - private: - // Internal helper for maintaining consistent received and total sizes. - void UpdateSize(int64 size); - - // Request ID assigned by the ResourceDispatcherHost. - int32 save_id_; - - // Full path to the save item file. - FilePath full_path_; - - // Short display version of the file. - FilePath file_name_; - - // The URL for this save item. - GURL url_; - GURL referrer_; - - // Total bytes expected. - int64 total_bytes_; - - // Current received bytes. - int64 received_bytes_; - - // The current state of this save item. - SaveState state_; - - // Specifies if this name is a final or not. - bool has_final_name_; - - // Flag indicates whether SaveItem has error while in saving process. - bool is_success_; - - SaveFileCreateInfo::SaveFileSource save_source_; - - // Our owning object. - SavePackage* package_; - - DISALLOW_COPY_AND_ASSIGN(SaveItem); -}; - -#endif // CHROME_BROWSER_DOWNLOAD_SAVE_ITEM_H__ diff --git a/chrome/browser/download/save_package.cc b/chrome/browser/download/save_package.cc deleted file mode 100644 index 8e37206..0000000 --- a/chrome/browser/download/save_package.cc +++ /dev/null @@ -1,1476 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/download/save_package.h" - -#include <algorithm> - -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/i18n/file_util_icu.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/stl_util-inl.h" -#include "base/string_piece.h" -#include "base/string_split.h" -#include "base/sys_string_conversions.h" -#include "base/task.h" -#include "base/threading/thread.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/download/download_item.h" -#include "chrome/browser/download/download_item_model.h" -#include "chrome/browser/download/download_manager.h" -#include "chrome/browser/download/download_prefs.h" -#include "chrome/browser/download/download_util.h" -#include "chrome/browser/download/save_file.h" -#include "chrome/browser/download/save_file_manager.h" -#include "chrome/browser/download/save_item.h" -#include "chrome/browser/net/url_fixer_upper.h" -#include "chrome/browser/platform_util.h" -#include "chrome/browser/prefs/pref_member.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/tab_contents/tab_util.h" -#include "chrome/browser/ui/download/download_tab_helper.h" -#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" -#include "chrome/common/chrome_notification_types.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/render_messages.h" -#include "chrome/common/url_constants.h" -#include "content/browser/browser_thread.h" -#include "content/browser/renderer_host/render_process_host.h" -#include "content/browser/renderer_host/render_view_host.h" -#include "content/browser/renderer_host/render_view_host_delegate.h" -#include "content/browser/renderer_host/resource_dispatcher_host.h" -#include "content/browser/tab_contents/tab_contents.h" -#include "content/common/notification_service.h" -#include "grit/generated_resources.h" -#include "net/base/io_buffer.h" -#include "net/base/mime_util.h" -#include "net/base/net_util.h" -#include "net/url_request/url_request_context.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebPageSerializerClient.h" -#include "ui/base/l10n/l10n_util.h" - -using base::Time; -using WebKit::WebPageSerializerClient; - -namespace { - -// A counter for uniquely identifying each save package. -int g_save_package_id = 0; - -// Default name which will be used when we can not get proper name from -// resource URL. -const char kDefaultSaveName[] = "saved_resource"; - -const FilePath::CharType kDefaultHtmlExtension[] = -#if defined(OS_WIN) - FILE_PATH_LITERAL("htm"); -#else - FILE_PATH_LITERAL("html"); -#endif - -// Maximum number of file ordinal number. I think it's big enough for resolving -// name-conflict files which has same base file name. -const int32 kMaxFileOrdinalNumber = 9999; - -// Maximum length for file path. Since Windows have MAX_PATH limitation for -// file path, we need to make sure length of file path of every saved file -// is less than MAX_PATH -#if defined(OS_WIN) -const uint32 kMaxFilePathLength = MAX_PATH - 1; -#elif defined(OS_POSIX) -const uint32 kMaxFilePathLength = PATH_MAX - 1; -#endif - -// Maximum length for file ordinal number part. Since we only support the -// maximum 9999 for ordinal number, which means maximum file ordinal number part -// should be "(9998)", so the value is 6. -const uint32 kMaxFileOrdinalNumberPartLength = 6; - -// If false, we don't prompt the user as to where to save the file. This -// exists only for testing. -bool g_should_prompt_for_filename = true; - -// Indexes used for specifying which element in the extensions dropdown -// the user chooses when picking a save type. -const int kSelectFileHtmlOnlyIndex = 1; -const int kSelectFileCompleteIndex = 2; - -// Used for mapping between SavePackageType constants and the indexes above. -const SavePackage::SavePackageType kIndexToSaveType[] = { - SavePackage::SAVE_TYPE_UNKNOWN, - SavePackage::SAVE_AS_ONLY_HTML, - SavePackage::SAVE_AS_COMPLETE_HTML, -}; - -// Used for mapping between the IDS_ string identifiers and the indexes above. -const int kIndexToIDS[] = { - 0, IDS_SAVE_PAGE_DESC_HTML_ONLY, IDS_SAVE_PAGE_DESC_COMPLETE, -}; - -int SavePackageTypeToIndex(SavePackage::SavePackageType type) { - for (size_t i = 0; i < arraysize(kIndexToSaveType); ++i) { - if (kIndexToSaveType[i] == type) - return i; - } - NOTREACHED(); - return -1; -} - -// Strip current ordinal number, if any. Should only be used on pure -// file names, i.e. those stripped of their extensions. -// TODO(estade): improve this to not choke on alternate encodings. -FilePath::StringType StripOrdinalNumber( - const FilePath::StringType& pure_file_name) { - FilePath::StringType::size_type r_paren_index = - pure_file_name.rfind(FILE_PATH_LITERAL(')')); - FilePath::StringType::size_type l_paren_index = - pure_file_name.rfind(FILE_PATH_LITERAL('(')); - if (l_paren_index >= r_paren_index) - return pure_file_name; - - for (FilePath::StringType::size_type i = l_paren_index + 1; - i != r_paren_index; ++i) { - if (!IsAsciiDigit(pure_file_name[i])) - return pure_file_name; - } - - return pure_file_name.substr(0, l_paren_index); -} - -// Check whether we can save page as complete-HTML for the contents which -// have specified a MIME type. Now only contents which have the MIME type -// "text/html" can be saved as complete-HTML. -bool CanSaveAsComplete(const std::string& contents_mime_type) { - return contents_mime_type == "text/html" || - contents_mime_type == "application/xhtml+xml"; -} - -} // namespace - -SavePackage::SavePackage(TabContentsWrapper* wrapper, - SavePackageType save_type, - const FilePath& file_full_path, - const FilePath& directory_full_path) - : TabContentsObserver(wrapper->tab_contents()), - wrapper_(wrapper), - file_manager_(NULL), - download_(NULL), - page_url_(GetUrlToBeSaved()), - saved_main_file_path_(file_full_path), - saved_main_directory_path_(directory_full_path), - title_(tab_contents()->GetTitle()), - finished_(false), - user_canceled_(false), - disk_error_occurred_(false), - save_type_(save_type), - all_save_items_count_(0), - wait_state_(INITIALIZE), - tab_id_(tab_contents()->GetRenderProcessHost()->id()), - unique_id_(g_save_package_id++), - ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { - DCHECK(page_url_.is_valid()); - DCHECK(save_type_ == SAVE_AS_ONLY_HTML || - save_type_ == SAVE_AS_COMPLETE_HTML); - DCHECK(!saved_main_file_path_.empty() && - saved_main_file_path_.value().length() <= kMaxFilePathLength); - DCHECK(!saved_main_directory_path_.empty() && - saved_main_directory_path_.value().length() < kMaxFilePathLength); - InternalInit(); -} - -SavePackage::SavePackage(TabContentsWrapper* wrapper) - : TabContentsObserver(wrapper->tab_contents()), - wrapper_(wrapper), - file_manager_(NULL), - download_(NULL), - page_url_(GetUrlToBeSaved()), - title_(tab_contents()->GetTitle()), - finished_(false), - user_canceled_(false), - disk_error_occurred_(false), - save_type_(SAVE_TYPE_UNKNOWN), - all_save_items_count_(0), - wait_state_(INITIALIZE), - tab_id_(tab_contents()->GetRenderProcessHost()->id()), - unique_id_(g_save_package_id++), - ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { - DCHECK(page_url_.is_valid()); - InternalInit(); -} - -// This is for testing use. Set |finished_| as true because we don't want -// method Cancel to be be called in destructor in test mode. -// We also don't call InternalInit(). -SavePackage::SavePackage(TabContentsWrapper* wrapper, - const FilePath& file_full_path, - const FilePath& directory_full_path) - : TabContentsObserver(wrapper->tab_contents()), - wrapper_(wrapper), - file_manager_(NULL), - download_(NULL), - saved_main_file_path_(file_full_path), - saved_main_directory_path_(directory_full_path), - finished_(true), - user_canceled_(false), - disk_error_occurred_(false), - save_type_(SAVE_TYPE_UNKNOWN), - all_save_items_count_(0), - wait_state_(INITIALIZE), - tab_id_(0), - unique_id_(g_save_package_id++), - ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { -} - -SavePackage::~SavePackage() { - // Stop receiving saving job's updates - if (!finished_ && !canceled()) { - // Unexpected quit. - Cancel(true); - } - - DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + - completed_count() + - in_process_count())); - // Free all SaveItems. - while (!waiting_item_queue_.empty()) { - // We still have some items which are waiting for start to save. - SaveItem* save_item = waiting_item_queue_.front(); - waiting_item_queue_.pop(); - delete save_item; - } - - STLDeleteValues(&saved_success_items_); - STLDeleteValues(&in_progress_items_); - STLDeleteValues(&saved_failed_items_); - - // The DownloadItem is owned by DownloadManager. - download_ = NULL; - - file_manager_ = NULL; - - // If there's an outstanding save dialog, make sure it doesn't call us back - // now that we're gone. - if (select_file_dialog_.get()) - select_file_dialog_->ListenerDestroyed(); -} - -// Retrieves the URL to be saved from tab_contents_ variable. -GURL SavePackage::GetUrlToBeSaved() { - // Instead of using tab_contents_.GetURL here, we use url() - // (which is the "real" url of the page) - // from the NavigationEntry because it reflects its' origin - // rather than the displayed one (returned by GetURL) which may be - // different (like having "view-source:" on the front). - NavigationEntry* active_entry = - tab_contents()->controller().GetActiveEntry(); - return active_entry->url(); -} - -// Cancel all in progress request, might be called by user or internal error. -void SavePackage::Cancel(bool user_action) { - if (!canceled()) { - if (user_action) - user_canceled_ = true; - else - disk_error_occurred_ = true; - Stop(); - } -} - -// Init() can be called directly, or indirectly via GetSaveInfo(). In both -// cases, we need file_manager_ to be initialized, so we do this first. -void SavePackage::InternalInit() { - ResourceDispatcherHost* rdh = g_browser_process->resource_dispatcher_host(); - if (!rdh) { - NOTREACHED(); - return; - } - - file_manager_ = rdh->save_file_manager(); - if (!file_manager_) { - NOTREACHED(); - return; - } -} - -// Initialize the SavePackage. -bool SavePackage::Init() { - // Set proper running state. - if (wait_state_ != INITIALIZE) - return false; - - wait_state_ = START_PROCESS; - - // Initialize the request context and resource dispatcher. - Profile* profile = tab_contents()->profile(); - if (!profile) { - NOTREACHED(); - return false; - } - - // Create the fake DownloadItem and display the view. - DownloadManager* download_manager = - tab_contents()->profile()->GetDownloadManager(); - download_ = new DownloadItem(download_manager, - saved_main_file_path_, - page_url_, - profile->IsOffTheRecord()); - - // Transfer the ownership to the download manager. We need the DownloadItem - // to be alive as long as the Profile is alive. - download_manager->SavePageAsDownloadStarted(download_); - - wrapper_->download_tab_helper()->OnStartDownload(download_); - - // Check save type and process the save page job. - if (save_type_ == SAVE_AS_COMPLETE_HTML) { - // Get directory - DCHECK(!saved_main_directory_path_.empty()); - GetAllSavableResourceLinksForCurrentPage(); - } else { - wait_state_ = NET_FILES; - SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? - SaveFileCreateInfo::SAVE_FILE_FROM_FILE : - SaveFileCreateInfo::SAVE_FILE_FROM_NET; - SaveItem* save_item = new SaveItem(page_url_, - GURL(), - this, - save_source); - // Add this item to waiting list. - waiting_item_queue_.push(save_item); - all_save_items_count_ = 1; - download_->set_total_bytes(1); - - DoSavingProcess(); - } - - return true; -} - -// On POSIX, the length of |pure_file_name| + |file_name_ext| is further -// restricted by NAME_MAX. The maximum allowed path looks like: -// '/path/to/save_dir' + '/' + NAME_MAX. -uint32 SavePackage::GetMaxPathLengthForDirectory(const FilePath& base_dir) { -#if defined(OS_POSIX) - return std::min(kMaxFilePathLength, - static_cast<uint32>(base_dir.value().length()) + - NAME_MAX + 1); -#else - return kMaxFilePathLength; -#endif -} - -// File name is considered being consist of pure file name, dot and file -// extension name. File name might has no dot and file extension, or has -// multiple dot inside file name. The dot, which separates the pure file -// name and file extension name, is last dot in the whole file name. -// This function is for making sure the length of specified file path is not -// great than the specified maximum length of file path and getting safe pure -// file name part if the input pure file name is too long. -// The parameter |dir_path| specifies directory part of the specified -// file path. The parameter |file_name_ext| specifies file extension -// name part of the specified file path (including start dot). The parameter -// |max_file_path_len| specifies maximum length of the specified file path. -// The parameter |pure_file_name| input pure file name part of the specified -// file path. If the length of specified file path is great than -// |max_file_path_len|, the |pure_file_name| will output new pure file name -// part for making sure the length of specified file path is less than -// specified maximum length of file path. Return false if the function can -// not get a safe pure file name, otherwise it returns true. -bool SavePackage::GetSafePureFileName(const FilePath& dir_path, - const FilePath::StringType& file_name_ext, - uint32 max_file_path_len, - FilePath::StringType* pure_file_name) { - DCHECK(!pure_file_name->empty()); - int available_length = static_cast<int>(max_file_path_len - - dir_path.value().length() - - file_name_ext.length()); - // Need an extra space for the separator. - if (!file_util::EndsWithSeparator(dir_path)) - --available_length; - - // Plenty of room. - if (static_cast<int>(pure_file_name->length()) <= available_length) - return true; - - // Limited room. Truncate |pure_file_name| to fit. - if (available_length > 0) { - *pure_file_name = pure_file_name->substr(0, available_length); - return true; - } - - // Not enough room to even use a shortened |pure_file_name|. - pure_file_name->clear(); - return false; -} - -// Generate name for saving resource. -bool SavePackage::GenerateFileName(const std::string& disposition, - const GURL& url, - bool need_html_ext, - FilePath::StringType* generated_name) { - // TODO(jungshik): Figure out the referrer charset when having one - // makes sense and pass it to GetSuggestedFilename. - string16 suggested_name = - net::GetSuggestedFilename(url, disposition, "", "", - ASCIIToUTF16(kDefaultSaveName)); - - // TODO(evan): this code is totally wrong -- we should just generate - // Unicode filenames and do all this encoding switching at the end. - // However, I'm just shuffling wrong code around, at least not adding - // to it. -#if defined(OS_WIN) - FilePath file_path = FilePath(suggested_name); -#else - FilePath file_path = FilePath( - base::SysWideToNativeMB(UTF16ToWide(suggested_name))); -#endif - - DCHECK(!file_path.empty()); - FilePath::StringType pure_file_name = - file_path.RemoveExtension().BaseName().value(); - FilePath::StringType file_name_ext = file_path.Extension(); - - // If it is HTML resource, use ".htm{l,}" as its extension. - if (need_html_ext) { - file_name_ext = FILE_PATH_LITERAL("."); - file_name_ext.append(kDefaultHtmlExtension); - } - - // Need to make sure the suggested file name is not too long. - uint32 max_path = GetMaxPathLengthForDirectory(saved_main_directory_path_); - - // Get safe pure file name. - if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, - max_path, &pure_file_name)) - return false; - - FilePath::StringType file_name = pure_file_name + file_name_ext; - - // Check whether we already have same name. - if (file_name_set_.find(file_name) == file_name_set_.end()) { - file_name_set_.insert(file_name); - } else { - // Found same name, increase the ordinal number for the file name. - FilePath::StringType base_file_name = StripOrdinalNumber(pure_file_name); - - // We need to make sure the length of base file name plus maximum ordinal - // number path will be less than or equal to kMaxFilePathLength. - if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, - max_path - kMaxFileOrdinalNumberPartLength, &base_file_name)) - return false; - - // Prepare the new ordinal number. - uint32 ordinal_number; - FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name); - if (it == file_name_count_map_.end()) { - // First base-name-conflict resolving, use 1 as initial ordinal number. - file_name_count_map_[base_file_name] = 1; - ordinal_number = 1; - } else { - // We have met same base-name conflict, use latest ordinal number. - ordinal_number = it->second; - } - - if (ordinal_number > (kMaxFileOrdinalNumber - 1)) { - // Use a random file from temporary file. - FilePath temp_file; - file_util::CreateTemporaryFile(&temp_file); - file_name = temp_file.RemoveExtension().BaseName().value(); - // Get safe pure file name. - if (!GetSafePureFileName(saved_main_directory_path_, - FilePath::StringType(), - max_path, &file_name)) - return false; - } else { - for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) { - FilePath::StringType new_name = base_file_name + - StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext; - if (file_name_set_.find(new_name) == file_name_set_.end()) { - // Resolved name conflict. - file_name = new_name; - file_name_count_map_[base_file_name] = ++i; - break; - } - } - } - - file_name_set_.insert(file_name); - } - - DCHECK(!file_name.empty()); - generated_name->assign(file_name); - - return true; -} - -// We have received a message from SaveFileManager about a new saving job. We -// create a SaveItem and store it in our in_progress list. -void SavePackage::StartSave(const SaveFileCreateInfo* info) { - DCHECK(info && !info->url.is_empty()); - - SaveUrlItemMap::iterator it = in_progress_items_.find(info->url.spec()); - if (it == in_progress_items_.end()) { - // If not found, we must have cancel action. - DCHECK(canceled()); - return; - } - SaveItem* save_item = it->second; - - DCHECK(!saved_main_file_path_.empty()); - - save_item->SetSaveId(info->save_id); - save_item->SetTotalBytes(info->total_bytes); - - // Determine the proper path for a saving job, by choosing either the default - // save directory, or prompting the user. - DCHECK(!save_item->has_final_name()); - if (info->url != page_url_) { - FilePath::StringType generated_name; - // For HTML resource file, make sure it will have .htm as extension name, - // otherwise, when you open the saved page in Chrome again, download - // file manager will treat it as downloadable resource, and download it - // instead of opening it as HTML. - bool need_html_ext = - info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM; - if (!GenerateFileName(info->content_disposition, - GURL(info->url), - need_html_ext, - &generated_name)) { - // We can not generate file name for this SaveItem, so we cancel the - // saving page job if the save source is from serialized DOM data. - // Otherwise, it means this SaveItem is sub-resource type, we treat it - // as an error happened on saving. We can ignore this type error for - // sub-resource links which will be resolved as absolute links instead - // of local links in final saved contents. - if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) - Cancel(true); - else - SaveFinished(save_item->save_id(), 0, false); - return; - } - - // When saving page as only-HTML, we only have a SaveItem whose url - // must be page_url_. - DCHECK(save_type_ == SAVE_AS_COMPLETE_HTML); - DCHECK(!saved_main_directory_path_.empty()); - - // Now we get final name retrieved from GenerateFileName, we will use it - // rename the SaveItem. - FilePath final_name = saved_main_directory_path_.Append(generated_name); - save_item->Rename(final_name); - } else { - // It is the main HTML file, use the name chosen by the user. - save_item->Rename(saved_main_file_path_); - } - - // If the save source is from file system, inform SaveFileManager to copy - // corresponding file to the file path which this SaveItem specifies. - if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::SaveLocalFile, - save_item->url(), - save_item->save_id(), - tab_id())); - return; - } - - // Check whether we begin to require serialized HTML data. - if (save_type_ == SAVE_AS_COMPLETE_HTML && wait_state_ == HTML_DATA) { - // Inform backend to serialize the all frames' DOM and send serialized - // HTML data back. - GetSerializedHtmlDataForCurrentPageWithLocalLinks(); - } -} - -// Look up SaveItem by save id from in progress map. -SaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) { - if (in_process_count()) { - for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); - it != in_progress_items_.end(); ++it) { - SaveItem* save_item = it->second; - DCHECK(save_item->state() == SaveItem::IN_PROGRESS); - if (save_item->save_id() == save_id) - return save_item; - } - } - return NULL; -} - -// Remove SaveItem from in progress map and put it to saved map. -void SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) { - SaveUrlItemMap::iterator it = in_progress_items_.find( - save_item->url().spec()); - DCHECK(it != in_progress_items_.end()); - DCHECK(save_item == it->second); - in_progress_items_.erase(it); - - if (save_item->success()) { - // Add it to saved_success_items_. - DCHECK(saved_success_items_.find(save_item->save_id()) == - saved_success_items_.end()); - saved_success_items_[save_item->save_id()] = save_item; - } else { - // Add it to saved_failed_items_. - DCHECK(saved_failed_items_.find(save_item->url().spec()) == - saved_failed_items_.end()); - saved_failed_items_[save_item->url().spec()] = save_item; - } -} - -// Called for updating saving state. -bool SavePackage::UpdateSaveProgress(int32 save_id, - int64 size, - bool write_success) { - // Because we might have canceled this saving job before, - // so we might not find corresponding SaveItem. - SaveItem* save_item = LookupItemInProcessBySaveId(save_id); - if (!save_item) - return false; - - save_item->Update(size); - - // If we got disk error, cancel whole save page job. - if (!write_success) { - // Cancel job with reason of disk error. - Cancel(false); - } - return true; -} - -// Stop all page saving jobs that are in progress and instruct the file thread -// to delete all saved files. -void SavePackage::Stop() { - // If we haven't moved out of the initial state, there's nothing to cancel and - // there won't be valid pointers for file_manager_ or download_. - if (wait_state_ == INITIALIZE) - return; - - // When stopping, if it still has some items in in_progress, cancel them. - DCHECK(canceled()); - if (in_process_count()) { - SaveUrlItemMap::iterator it = in_progress_items_.begin(); - for (; it != in_progress_items_.end(); ++it) { - SaveItem* save_item = it->second; - DCHECK(save_item->state() == SaveItem::IN_PROGRESS); - save_item->Cancel(); - } - // Remove all in progress item to saved map. For failed items, they will - // be put into saved_failed_items_, for successful item, they will be put - // into saved_success_items_. - while (in_process_count()) - PutInProgressItemToSavedMap(in_progress_items_.begin()->second); - } - - // This vector contains the save ids of the save files which SaveFileManager - // needs to remove from its save_file_map_. - SaveIDList save_ids; - for (SavedItemMap::iterator it = saved_success_items_.begin(); - it != saved_success_items_.end(); ++it) - save_ids.push_back(it->first); - for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); - it != saved_failed_items_.end(); ++it) - save_ids.push_back(it->second->save_id()); - - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::RemoveSavedFileFromFileMap, - save_ids)); - - finished_ = true; - wait_state_ = FAILED; - - // Inform the DownloadItem we have canceled whole save page job. - download_->Cancel(false); -} - -void SavePackage::CheckFinish() { - if (in_process_count() || finished_) - return; - - FilePath dir = (save_type_ == SAVE_AS_COMPLETE_HTML && - saved_success_items_.size() > 1) ? - saved_main_directory_path_ : FilePath(); - - // This vector contains the final names of all the successfully saved files - // along with their save ids. It will be passed to SaveFileManager to do the - // renaming job. - FinalNameList final_names; - for (SavedItemMap::iterator it = saved_success_items_.begin(); - it != saved_success_items_.end(); ++it) - final_names.push_back(std::make_pair(it->first, - it->second->full_path())); - - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::RenameAllFiles, - final_names, - dir, - tab_contents()->GetRenderProcessHost()->id(), - tab_contents()->render_view_host()->routing_id(), - id())); -} - -// Successfully finished all items of this SavePackage. -void SavePackage::Finish() { - // User may cancel the job when we're moving files to the final directory. - if (canceled()) - return; - - wait_state_ = SUCCESSFUL; - finished_ = true; - - // This vector contains the save ids of the save files which SaveFileManager - // needs to remove from its save_file_map_. - SaveIDList save_ids; - for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); - it != saved_failed_items_.end(); ++it) - save_ids.push_back(it->second->save_id()); - - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::RemoveSavedFileFromFileMap, - save_ids)); - - download_->OnAllDataSaved(all_save_items_count_); - download_->MarkAsComplete(); - - NotificationService::current()->Notify( - chrome::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, - Source<SavePackage>(this), - Details<GURL>(&page_url_)); -} - -// Called for updating end state. -void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) { - // Because we might have canceled this saving job before, - // so we might not find corresponding SaveItem. Just ignore it. - SaveItem* save_item = LookupItemInProcessBySaveId(save_id); - if (!save_item) - return; - - // Let SaveItem set end state. - save_item->Finish(size, is_success); - // Remove the associated save id and SavePackage. - file_manager_->RemoveSaveFile(save_id, save_item->url(), this); - - PutInProgressItemToSavedMap(save_item); - - // Inform the DownloadItem to update UI. - // We use the received bytes as number of saved files. - download_->Update(completed_count()); - - if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM && - save_item->url() == page_url_ && !save_item->received_bytes()) { - // If size of main HTML page is 0, treat it as disk error. - Cancel(false); - return; - } - - if (canceled()) { - DCHECK(finished_); - return; - } - - // Continue processing the save page job. - DoSavingProcess(); - - // Check whether we can successfully finish whole job. - CheckFinish(); -} - -// Sometimes, the net io will only call SaveFileManager::SaveFinished with -// save id -1 when it encounters error. Since in this case, save id will be -// -1, so we can only use URL to find which SaveItem is associated with -// this error. -// Saving an item failed. If it's a sub-resource, ignore it. If the error comes -// from serializing HTML data, then cancel saving page. -void SavePackage::SaveFailed(const GURL& save_url) { - SaveUrlItemMap::iterator it = in_progress_items_.find(save_url.spec()); - if (it == in_progress_items_.end()) { - NOTREACHED(); // Should not exist! - return; - } - SaveItem* save_item = it->second; - - save_item->Finish(0, false); - - PutInProgressItemToSavedMap(save_item); - - // Inform the DownloadItem to update UI. - // We use the received bytes as number of saved files. - download_->Update(completed_count()); - - if (save_type_ == SAVE_AS_ONLY_HTML || - save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { - // We got error when saving page. Treat it as disk error. - Cancel(true); - } - - if (canceled()) { - DCHECK(finished_); - return; - } - - // Continue processing the save page job. - DoSavingProcess(); - - CheckFinish(); -} - -void SavePackage::SaveCanceled(SaveItem* save_item) { - // Call the RemoveSaveFile in UI thread. - file_manager_->RemoveSaveFile(save_item->save_id(), - save_item->url(), - this); - if (save_item->save_id() != -1) - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::CancelSave, - save_item->save_id())); -} - -// Initiate a saving job of a specific URL. We send the request to -// SaveFileManager, which will dispatch it to different approach according to -// the save source. Parameter process_all_remaining_items indicates whether -// we need to save all remaining items. -void SavePackage::SaveNextFile(bool process_all_remaining_items) { - DCHECK(tab_contents()); - DCHECK(waiting_item_queue_.size()); - - do { - // Pop SaveItem from waiting list. - SaveItem* save_item = waiting_item_queue_.front(); - waiting_item_queue_.pop(); - - // Add the item to in_progress_items_. - SaveUrlItemMap::iterator it = in_progress_items_.find( - save_item->url().spec()); - DCHECK(it == in_progress_items_.end()); - in_progress_items_[save_item->url().spec()] = save_item; - save_item->Start(); - file_manager_->SaveURL(save_item->url(), - save_item->referrer(), - tab_contents()->GetRenderProcessHost()->id(), - routing_id(), - save_item->save_source(), - save_item->full_path(), - tab_contents()->profile()->GetResourceContext(), - this); - } while (process_all_remaining_items && waiting_item_queue_.size()); -} - - -// Open download page in windows explorer on file thread, to avoid blocking the -// user interface. -void SavePackage::ShowDownloadInShell() { - DCHECK(file_manager_); - DCHECK(finished_ && !canceled() && !saved_main_file_path_.empty()); - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); -#if defined(OS_MACOSX) - // Mac OS X requires opening downloads on the UI thread. - platform_util::ShowItemInFolder(saved_main_file_path_); -#else - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::OnShowSavedFileInShell, - saved_main_file_path_)); -#endif -} - -// Calculate the percentage of whole save page job. -int SavePackage::PercentComplete() { - if (!all_save_items_count_) - return 0; - else if (!in_process_count()) - return 100; - else - return completed_count() / all_save_items_count_; -} - -// Continue processing the save page job after one SaveItem has been -// finished. -void SavePackage::DoSavingProcess() { - if (save_type_ == SAVE_AS_COMPLETE_HTML) { - // We guarantee that images and JavaScripts must be downloaded first. - // So when finishing all those sub-resources, we will know which - // sub-resource's link can be replaced with local file path, which - // sub-resource's link need to be replaced with absolute URL which - // point to its internet address because it got error when saving its data. - SaveItem* save_item = NULL; - // Start a new SaveItem job if we still have job in waiting queue. - if (waiting_item_queue_.size()) { - DCHECK(wait_state_ == NET_FILES); - save_item = waiting_item_queue_.front(); - if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { - SaveNextFile(false); - } else if (!in_process_count()) { - // If there is no in-process SaveItem, it means all sub-resources - // have been processed. Now we need to start serializing HTML DOM - // for the current page to get the generated HTML data. - wait_state_ = HTML_DATA; - // All non-HTML resources have been finished, start all remaining - // HTML files. - SaveNextFile(true); - } - } else if (in_process_count()) { - // Continue asking for HTML data. - DCHECK(wait_state_ == HTML_DATA); - } - } else { - // Save as HTML only. - DCHECK(wait_state_ == NET_FILES); - DCHECK(save_type_ == SAVE_AS_ONLY_HTML); - if (waiting_item_queue_.size()) { - DCHECK(all_save_items_count_ == waiting_item_queue_.size()); - SaveNextFile(false); - } - } -} - -bool SavePackage::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(SavePackage, message) - IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks, - OnReceivedSavableResourceLinksForCurrentPage) - IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData, - OnReceivedSerializedHtmlData) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -// After finishing all SaveItems which need to get data from net. -// We collect all URLs which have local storage and send the -// map:(originalURL:currentLocalPath) to render process (backend). -// Then render process will serialize DOM and send data to us. -void SavePackage::GetSerializedHtmlDataForCurrentPageWithLocalLinks() { - if (wait_state_ != HTML_DATA) - return; - std::vector<GURL> saved_links; - std::vector<FilePath> saved_file_paths; - int successful_started_items_count = 0; - - // Collect all saved items which have local storage. - // First collect the status of all the resource files and check whether they - // have created local files although they have not been completely saved. - // If yes, the file can be saved. Otherwise, there is a disk error, so we - // need to cancel the page saving job. - for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); - it != in_progress_items_.end(); ++it) { - DCHECK(it->second->save_source() == - SaveFileCreateInfo::SAVE_FILE_FROM_DOM); - if (it->second->has_final_name()) - successful_started_items_count++; - saved_links.push_back(it->second->url()); - saved_file_paths.push_back(it->second->file_name()); - } - - // If not all file of HTML resource have been started, then wait. - if (successful_started_items_count != in_process_count()) - return; - - // Collect all saved success items. - for (SavedItemMap::iterator it = saved_success_items_.begin(); - it != saved_success_items_.end(); ++it) { - DCHECK(it->second->has_final_name()); - saved_links.push_back(it->second->url()); - saved_file_paths.push_back(it->second->file_name()); - } - - // Get the relative directory name. - FilePath relative_dir_name = saved_main_directory_path_.BaseName(); - - Send(new ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks( - routing_id(), saved_links, saved_file_paths, relative_dir_name)); -} - -// Process the serialized HTML content data of a specified web page -// retrieved from render process. -void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url, - const std::string& data, - int32 status) { - WebPageSerializerClient::PageSerializationStatus flag = - static_cast<WebPageSerializerClient::PageSerializationStatus>(status); - // Check current state. - if (wait_state_ != HTML_DATA) - return; - - int id = tab_id(); - // If the all frames are finished saving, we need to close the - // remaining SaveItems. - if (flag == WebPageSerializerClient::AllFramesAreFinished) { - for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); - it != in_progress_items_.end(); ++it) { - VLOG(20) << " " << __FUNCTION__ << "()" - << " save_id = " << it->second->save_id() - << " url = \"" << it->second->url().spec() << "\""; - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::SaveFinished, - it->second->save_id(), - it->second->url(), - id, - true)); - } - return; - } - - SaveUrlItemMap::iterator it = in_progress_items_.find(frame_url.spec()); - if (it == in_progress_items_.end()) - return; - SaveItem* save_item = it->second; - DCHECK(save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM); - - if (!data.empty()) { - // Prepare buffer for saving HTML data. - scoped_refptr<net::IOBuffer> new_data(new net::IOBuffer(data.size())); - memcpy(new_data->data(), data.data(), data.size()); - - // Call write file functionality in file thread. - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::UpdateSaveProgress, - save_item->save_id(), - new_data, - static_cast<int>(data.size()))); - } - - // Current frame is completed saving, call finish in file thread. - if (flag == WebPageSerializerClient::CurrentFrameIsFinished) { - VLOG(20) << " " << __FUNCTION__ << "()" - << " save_id = " << save_item->save_id() - << " url = \"" << save_item->url().spec() << "\""; - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(file_manager_, - &SaveFileManager::SaveFinished, - save_item->save_id(), - save_item->url(), - id, - true)); - } -} - -// Ask for all savable resource links from backend, include main frame and -// sub-frame. -void SavePackage::GetAllSavableResourceLinksForCurrentPage() { - if (wait_state_ != START_PROCESS) - return; - - wait_state_ = RESOURCES_LIST; - Send(new ViewMsg_GetAllSavableResourceLinksForCurrentPage(routing_id(), - page_url_)); -} - -// Give backend the lists which contain all resource links that have local -// storage, after which, render process will serialize DOM for generating -// HTML data. -void SavePackage::OnReceivedSavableResourceLinksForCurrentPage( - const std::vector<GURL>& resources_list, - const std::vector<GURL>& referrers_list, - const std::vector<GURL>& frames_list) { - if (wait_state_ != RESOURCES_LIST) - return; - - DCHECK(resources_list.size() == referrers_list.size()); - all_save_items_count_ = static_cast<int>(resources_list.size()) + - static_cast<int>(frames_list.size()); - - // We use total bytes as the total number of files we want to save. - download_->set_total_bytes(all_save_items_count_); - - if (all_save_items_count_) { - // Put all sub-resources to wait list. - for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) { - const GURL& u = resources_list[i]; - DCHECK(u.is_valid()); - SaveFileCreateInfo::SaveFileSource save_source = u.SchemeIsFile() ? - SaveFileCreateInfo::SAVE_FILE_FROM_FILE : - SaveFileCreateInfo::SAVE_FILE_FROM_NET; - SaveItem* save_item = new SaveItem(u, referrers_list[i], - this, save_source); - waiting_item_queue_.push(save_item); - } - // Put all HTML resources to wait list. - for (int i = 0; i < static_cast<int>(frames_list.size()); ++i) { - const GURL& u = frames_list[i]; - DCHECK(u.is_valid()); - SaveItem* save_item = new SaveItem(u, GURL(), - this, SaveFileCreateInfo::SAVE_FILE_FROM_DOM); - waiting_item_queue_.push(save_item); - } - wait_state_ = NET_FILES; - DoSavingProcess(); - } else { - // No resource files need to be saved, treat it as user cancel. - Cancel(true); - } -} - -void SavePackage::SetShouldPromptUser(bool should_prompt) { - g_should_prompt_for_filename = should_prompt; -} - -FilePath SavePackage::GetSuggestedNameForSaveAs( - bool can_save_as_complete, - const std::string& contents_mime_type) { - FilePath name_with_proper_ext = - FilePath::FromWStringHack(UTF16ToWideHack(title_)); - - // If the page's title matches its URL, use the URL. Try to use the last path - // component or if there is none, the domain as the file name. - // Normally we want to base the filename on the page title, or if it doesn't - // exist, on the URL. It's not easy to tell if the page has no title, because - // if the page has no title, TabContents::GetTitle() will return the page's - // URL (adjusted for display purposes). Therefore, we convert the "title" - // back to a URL, and if it matches the original page URL, we know the page - // had no title (or had a title equal to its URL, which is fine to treat - // similarly). - GURL fixed_up_title_url = - URLFixerUpper::FixupURL(UTF16ToUTF8(title_), std::string()); - - if (page_url_ == fixed_up_title_url) { - std::string url_path; - std::vector<std::string> url_parts; - base::SplitString(page_url_.path(), '/', &url_parts); - if (!url_parts.empty()) { - for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) { - url_path = url_parts[i]; - if (!url_path.empty()) - break; - } - } - if (url_path.empty()) - url_path = page_url_.host(); - name_with_proper_ext = FilePath::FromWStringHack(UTF8ToWide(url_path)); - } - - // Ask user for getting final saving name. - name_with_proper_ext = EnsureMimeExtension(name_with_proper_ext, - contents_mime_type); - // Adjust extension for complete types. - if (can_save_as_complete) - name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext); - - FilePath::StringType file_name = name_with_proper_ext.value(); - file_util::ReplaceIllegalCharactersInPath(&file_name, ' '); - return FilePath(file_name); -} - -FilePath SavePackage::EnsureHtmlExtension(const FilePath& name) { - // If the file name doesn't have an extension suitable for HTML files, - // append one. - FilePath::StringType ext = name.Extension(); - if (!ext.empty()) - ext.erase(ext.begin()); // Erase preceding '.'. - std::string mime_type; - if (!net::GetMimeTypeFromExtension(ext, &mime_type) || - !CanSaveAsComplete(mime_type)) { - return FilePath(name.value() + FILE_PATH_LITERAL(".") + - kDefaultHtmlExtension); - } - return name; -} - -FilePath SavePackage::EnsureMimeExtension(const FilePath& name, - const std::string& contents_mime_type) { - // Start extension at 1 to skip over period if non-empty. - FilePath::StringType ext = name.Extension().length() ? - name.Extension().substr(1) : name.Extension(); - FilePath::StringType suggested_extension = - ExtensionForMimeType(contents_mime_type); - std::string mime_type; - if (!suggested_extension.empty() && - (!net::GetMimeTypeFromExtension(ext, &mime_type) || - !IsSavableContents(mime_type))) { - // Extension is absent or needs to be updated. - return FilePath(name.value() + FILE_PATH_LITERAL(".") + - suggested_extension); - } - return name; -} - -const FilePath::CharType* SavePackage::ExtensionForMimeType( - const std::string& contents_mime_type) { - static const struct { - const FilePath::CharType *mime_type; - const FilePath::CharType *suggested_extension; - } extensions[] = { - { FILE_PATH_LITERAL("text/html"), kDefaultHtmlExtension }, - { FILE_PATH_LITERAL("text/xml"), FILE_PATH_LITERAL("xml") }, - { FILE_PATH_LITERAL("application/xhtml+xml"), FILE_PATH_LITERAL("xhtml") }, - { FILE_PATH_LITERAL("text/plain"), FILE_PATH_LITERAL("txt") }, - { FILE_PATH_LITERAL("text/css"), FILE_PATH_LITERAL("css") }, - }; -#if defined(OS_POSIX) - FilePath::StringType mime_type(contents_mime_type); -#elif defined(OS_WIN) - FilePath::StringType mime_type(UTF8ToWide(contents_mime_type)); -#endif // OS_WIN - for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) { - if (mime_type == extensions[i].mime_type) - return extensions[i].suggested_extension; - } - return FILE_PATH_LITERAL(""); -} - - - -// static. -// Check whether the preference has the preferred directory for saving file. If -// not, initialize it with default directory. -FilePath SavePackage::GetSaveDirPreference(PrefService* prefs) { - DCHECK(prefs); - - if (!prefs->FindPreference(prefs::kSaveFileDefaultDirectory)) { - DCHECK(prefs->FindPreference(prefs::kDownloadDefaultDirectory)); - FilePath default_save_path = prefs->GetFilePath( - prefs::kDownloadDefaultDirectory); - prefs->RegisterFilePathPref(prefs::kSaveFileDefaultDirectory, - default_save_path, - PrefService::UNSYNCABLE_PREF); - } - - // Get the directory from preference. - FilePath save_file_path = prefs->GetFilePath( - prefs::kSaveFileDefaultDirectory); - DCHECK(!save_file_path.empty()); - - return save_file_path; -} - -void SavePackage::GetSaveInfo() { - // Can't use tab_contents_ in the file thread, so get the data that we need - // before calling to it. - PrefService* prefs = tab_contents()->profile()->GetPrefs(); - FilePath website_save_dir = GetSaveDirPreference(prefs); - FilePath download_save_dir = prefs->GetFilePath( - prefs::kDownloadDefaultDirectory); - std::string mime_type = tab_contents()->contents_mime_type(); - - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(this, &SavePackage::CreateDirectoryOnFileThread, - website_save_dir, download_save_dir, mime_type)); -} - -void SavePackage::CreateDirectoryOnFileThread( - const FilePath& website_save_dir, - const FilePath& download_save_dir, - const std::string& mime_type) { - FilePath save_dir; - // If the default html/websites save folder doesn't exist... - if (!file_util::DirectoryExists(website_save_dir)) { - // If the default download dir doesn't exist, create it. - if (!file_util::DirectoryExists(download_save_dir)) - file_util::CreateDirectory(download_save_dir); - save_dir = download_save_dir; - } else { - // If it does exist, use the default save dir param. - save_dir = website_save_dir; - } - - bool can_save_as_complete = CanSaveAsComplete(mime_type); - FilePath suggested_filename = GetSuggestedNameForSaveAs(can_save_as_complete, - mime_type); - FilePath::StringType pure_file_name = - suggested_filename.RemoveExtension().BaseName().value(); - FilePath::StringType file_name_ext = suggested_filename.Extension(); - - // Need to make sure the suggested file name is not too long. - uint32 max_path = GetMaxPathLengthForDirectory(save_dir); - - if (GetSafePureFileName(save_dir, file_name_ext, max_path, &pure_file_name)) { - save_dir = save_dir.Append(pure_file_name + file_name_ext); - } else { - // Cannot create a shorter filename. This will cause the save as operation - // to fail unless the user pick a shorter name. Continuing even though it - // will fail because returning means no save as popup for the user, which - // is even more confusing. This case should be rare though. - save_dir = save_dir.Append(suggested_filename); - } - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod(this, &SavePackage::ContinueGetSaveInfo, save_dir, - can_save_as_complete)); -} - -void SavePackage::ContinueGetSaveInfo(const FilePath& suggested_path, - bool can_save_as_complete) { - // The TabContents which owns this SavePackage may have disappeared during - // the UI->FILE->UI thread hop of - // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo. - if (!tab_contents()) - return; - DownloadPrefs* download_prefs = - tab_contents()->profile()->GetDownloadManager()->download_prefs(); - int file_type_index = - SavePackageTypeToIndex( - static_cast<SavePackageType>(download_prefs->save_file_type())); - DCHECK_NE(-1, file_type_index); - - SelectFileDialog::FileTypeInfo file_type_info; - FilePath::StringType default_extension; - - // If the contents can not be saved as complete-HTML, do not show the - // file filters. - if (can_save_as_complete) { - bool add_extra_extension = false; - FilePath::StringType extra_extension; - if (!suggested_path.Extension().empty() && - suggested_path.Extension().compare(FILE_PATH_LITERAL("htm")) && - suggested_path.Extension().compare(FILE_PATH_LITERAL("html"))) { - add_extra_extension = true; - extra_extension = suggested_path.Extension().substr(1); - } - - file_type_info.extensions.resize(2); - file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( - FILE_PATH_LITERAL("htm")); - file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( - FILE_PATH_LITERAL("html")); - - if (add_extra_extension) { - file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( - extra_extension); - } - - file_type_info.extension_description_overrides.push_back( - l10n_util::GetStringUTF16(kIndexToIDS[kSelectFileCompleteIndex - 1])); - file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( - FILE_PATH_LITERAL("htm")); - file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( - FILE_PATH_LITERAL("html")); - - if (add_extra_extension) { - file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( - extra_extension); - } - - file_type_info.extension_description_overrides.push_back( - l10n_util::GetStringUTF16(kIndexToIDS[kSelectFileCompleteIndex])); - file_type_info.include_all_files = false; - default_extension = kDefaultHtmlExtension; - } else { - file_type_info.extensions.resize(1); - file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( - suggested_path.Extension()); - - if (!file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1][0].empty()) { - // Drop the . - file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1][0].erase(0, 1); - } - - file_type_info.include_all_files = true; - file_type_index = 1; - } - - if (g_should_prompt_for_filename) { - if (!select_file_dialog_.get()) - select_file_dialog_ = SelectFileDialog::Create(this); - select_file_dialog_->SelectFile(SelectFileDialog::SELECT_SAVEAS_FILE, - string16(), - suggested_path, - &file_type_info, - file_type_index, - default_extension, - tab_contents(), - platform_util::GetTopLevel( - tab_contents()->GetNativeView()), - NULL); - } else { - // Just use 'suggested_path' instead of opening the dialog prompt. - ContinueSave(suggested_path, file_type_index); - } -} - -// Called after the save file dialog box returns. -void SavePackage::ContinueSave(const FilePath& final_name, - int index) { - // Ensure the filename is safe. - saved_main_file_path_ = final_name; - download_util::GenerateSafeFileName(tab_contents()->contents_mime_type(), - &saved_main_file_path_); - - // The option index is not zero-based. - DCHECK(index >= kSelectFileHtmlOnlyIndex && - index <= kSelectFileCompleteIndex); - - saved_main_directory_path_ = saved_main_file_path_.DirName(); - - PrefService* prefs = tab_contents()->profile()->GetPrefs(); - StringPrefMember save_file_path; - save_file_path.Init(prefs::kSaveFileDefaultDirectory, prefs, NULL); -#if defined(OS_POSIX) - std::string path_string = saved_main_directory_path_.value(); -#elif defined(OS_WIN) - std::string path_string = WideToUTF8(saved_main_directory_path_.value()); -#endif - // If user change the default saving directory, we will remember it just - // like IE and FireFox. - if (!tab_contents()->profile()->IsOffTheRecord() && - save_file_path.GetValue() != path_string) { - save_file_path.SetValue(path_string); - } - - save_type_ = kIndexToSaveType[index]; - - prefs->SetInteger(prefs::kSaveFileType, save_type_); - - if (save_type_ == SavePackage::SAVE_AS_COMPLETE_HTML) { - // Make new directory for saving complete file. - saved_main_directory_path_ = saved_main_directory_path_.Append( - saved_main_file_path_.RemoveExtension().BaseName().value() + - FILE_PATH_LITERAL("_files")); - } - - Init(); -} - -// Static -bool SavePackage::IsSavableURL(const GURL& url) { - for (int i = 0; chrome::kSavableSchemes[i] != NULL; ++i) { - if (url.SchemeIs(chrome::kSavableSchemes[i])) { - return true; - } - } - return false; -} - -// Static -bool SavePackage::IsSavableContents(const std::string& contents_mime_type) { - // WebKit creates Document object when MIME type is application/xhtml+xml, - // so we also support this MIME type. - return contents_mime_type == "text/html" || - contents_mime_type == "text/xml" || - contents_mime_type == "application/xhtml+xml" || - contents_mime_type == "text/plain" || - contents_mime_type == "text/css" || - net::IsSupportedJavascriptMimeType(contents_mime_type.c_str()); -} - -// SelectFileDialog::Listener interface. -void SavePackage::FileSelected(const FilePath& path, - int index, void* params) { - ContinueSave(path, index); -} - -void SavePackage::FileSelectionCanceled(void* params) { -} diff --git a/chrome/browser/download/save_package.h b/chrome/browser/download/save_package.h deleted file mode 100644 index 74f5526..0000000 --- a/chrome/browser/download/save_package.h +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_PACKAGE_H_ -#define CHROME_BROWSER_DOWNLOAD_SAVE_PACKAGE_H_ -#pragma once - -#include <queue> -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/file_path.h" -#include "base/gtest_prod_util.h" -#include "base/hash_tables.h" -#include "base/memory/ref_counted.h" -#include "base/task.h" -#include "chrome/browser/ui/shell_dialogs.h" -#include "content/browser/tab_contents/tab_contents_observer.h" -#include "googleurl/src/gurl.h" - -class DownloadItem; -class DownloadManager; -class GURL; -class MessageLoop; -class PrefService; -class Profile; -struct SaveFileCreateInfo; -class SaveFileManager; -class SaveItem; -class SavePackage; -struct SavePackageParam; -class TabContentsWrapper; - -namespace base { -class Thread; -class Time; -} - - -// The SavePackage object manages the process of saving a page as only-html or -// complete-html and providing the information for displaying saving status. -// Saving page as only-html means means that we save web page to a single HTML -// file regardless internal sub resources and sub frames. -// Saving page as complete-html page means we save not only the main html file -// the user told it to save but also a directory for the auxiliary files such -// as all sub-frame html files, image files, css files and js files. -// -// Each page saving job may include one or multiple files which need to be -// saved. Each file is represented by a SaveItem, and all SaveItems are owned -// by the SavePackage. SaveItems are created when a user initiates a page -// saving job, and exist for the duration of one tab's life time. -class SavePackage : public base::RefCountedThreadSafe<SavePackage>, - public TabContentsObserver, - public SelectFileDialog::Listener { - public: - enum SavePackageType { - // The value of the save type before its set by the user. - SAVE_TYPE_UNKNOWN = -1, - // User chose to save only the HTML of the page. - SAVE_AS_ONLY_HTML = 0, - // User chose to save complete-html page. - SAVE_AS_COMPLETE_HTML = 1 - }; - - enum WaitState { - // State when created but not initialized. - INITIALIZE = 0, - // State when after initializing, but not yet saving. - START_PROCESS, - // Waiting on a list of savable resources from the backend. - RESOURCES_LIST, - // Waiting for data sent from net IO or from file system. - NET_FILES, - // Waiting for html DOM data sent from render process. - HTML_DATA, - // Saving page finished successfully. - SUCCESSFUL, - // Failed to save page. - FAILED - }; - - // Constructor for user initiated page saving. This constructor results in a - // SavePackage that will generate and sanitize a suggested name for the user - // in the "Save As" dialog box. - explicit SavePackage(TabContentsWrapper* wrapper); - - // This contructor is used only for testing. We can bypass the file and - // directory name generation / sanitization by providing well known paths - // better suited for tests. - SavePackage(TabContentsWrapper* wrapper, - SavePackageType save_type, - const FilePath& file_full_path, - const FilePath& directory_full_path); - - // Initialize the SavePackage. Returns true if it initializes properly. - // Need to make sure that this method must be called in the UI thread because - // using g_browser_process on a non-UI thread can cause crashes during - // shutdown. - bool Init(); - - void Cancel(bool user_action); - - void Finish(); - - // Notifications sent from the file thread to the UI thread. - void StartSave(const SaveFileCreateInfo* info); - bool UpdateSaveProgress(int32 save_id, int64 size, bool write_success); - void SaveFinished(int32 save_id, int64 size, bool is_success); - void SaveFailed(const GURL& save_url); - void SaveCanceled(SaveItem* save_item); - - // Rough percent complete, -1 means we don't know (since we didn't receive a - // total size). - int PercentComplete(); - - // Show or Open a saved page via the Windows shell. - void ShowDownloadInShell(); - - bool canceled() const { return user_canceled_ || disk_error_occurred_; } - bool finished() const { return finished_; } - SavePackageType save_type() const { return save_type_; } - int tab_id() const { return tab_id_; } - int id() const { return unique_id_; } - - void GetSaveInfo(); - - // Statics ------------------------------------------------------------------- - - // Used to disable prompting the user for a directory/filename of the saved - // web page. This is available for testing. - static void SetShouldPromptUser(bool should_prompt); - - // Check whether we can do the saving page operation for the specified URL. - static bool IsSavableURL(const GURL& url); - - // Check whether we can do the saving page operation for the contents which - // have the specified MIME type. - static bool IsSavableContents(const std::string& contents_mime_type); - - // SelectFileDialog::Listener ------------------------------------------------ - virtual void FileSelected(const FilePath& path, int index, void* params); - virtual void FileSelectionCanceled(void* params); - - private: - friend class base::RefCountedThreadSafe<SavePackage>; - - // For testing only. - SavePackage(TabContentsWrapper* wrapper, - const FilePath& file_full_path, - const FilePath& directory_full_path); - - virtual ~SavePackage(); - - // Notes from Init() above applies here as well. - void InternalInit(); - - void Stop(); - void CheckFinish(); - void SaveNextFile(bool process_all_remainder_items); - void DoSavingProcess(); - - // TabContentsObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message); - - // Return max length of a path for a specific base directory. - // This is needed on POSIX, which restrict the length of file names in - // addition to the restriction on the length of path names. - // |base_dir| is assumed to be a directory name with no trailing slash. - static uint32 GetMaxPathLengthForDirectory(const FilePath& base_dir); - - static bool GetSafePureFileName(const FilePath& dir_path, - const FilePath::StringType& file_name_ext, - uint32 max_file_path_len, - FilePath::StringType* pure_file_name); - - // Create a file name based on the response from the server. - bool GenerateFileName(const std::string& disposition, - const GURL& url, - bool need_html_ext, - FilePath::StringType* generated_name); - - // Get all savable resource links from current web page, include main - // frame and sub-frame. - void GetAllSavableResourceLinksForCurrentPage(); - // Get html data by serializing all frames of current page with lists - // which contain all resource links that have local copy. - void GetSerializedHtmlDataForCurrentPageWithLocalLinks(); - - SaveItem* LookupItemInProcessBySaveId(int32 save_id); - void PutInProgressItemToSavedMap(SaveItem* save_item); - - // Retrieves the URL to be saved from tab_contents_ variable. - GURL GetUrlToBeSaved(); - - void CreateDirectoryOnFileThread(const FilePath& website_save_dir, - const FilePath& download_save_dir, - const std::string& mime_type); - void ContinueGetSaveInfo(const FilePath& suggested_path, - bool can_save_as_complete); - void ContinueSave(const FilePath& final_name, int index); - - void OnReceivedSavableResourceLinksForCurrentPage( - const std::vector<GURL>& resources_list, - const std::vector<GURL>& referrers_list, - const std::vector<GURL>& frames_list); - - void OnReceivedSerializedHtmlData(const GURL& frame_url, - const std::string& data, - int32 status); - - - typedef base::hash_map<std::string, SaveItem*> SaveUrlItemMap; - // in_progress_items_ is map of all saving job in in-progress state. - SaveUrlItemMap in_progress_items_; - // saved_failed_items_ is map of all saving job which are failed. - SaveUrlItemMap saved_failed_items_; - - // The number of in process SaveItems. - int in_process_count() const { - return static_cast<int>(in_progress_items_.size()); - } - - // The number of all SaveItems which have completed, including success items - // and failed items. - int completed_count() const { - return static_cast<int>(saved_success_items_.size() + - saved_failed_items_.size()); - } - - // Retrieve the preference for the directory to save pages to. - static FilePath GetSaveDirPreference(PrefService* prefs); - - // Helper function for preparing suggested name for the SaveAs Dialog. The - // suggested name is determined by the web document's title. - FilePath GetSuggestedNameForSaveAs( - bool can_save_as_complete, - const std::string& contents_mime_type); - - // Ensures that the file name has a proper extension for HTML by adding ".htm" - // if necessary. - static FilePath EnsureHtmlExtension(const FilePath& name); - - // Ensures that the file name has a proper extension for supported formats - // if necessary. - static FilePath EnsureMimeExtension(const FilePath& name, - const std::string& contents_mime_type); - - // Returns extension for supported MIME types (for example, for "text/plain" - // it returns "txt"). - static const FilePath::CharType* ExtensionForMimeType( - const std::string& contents_mime_type); - - // Owning TabContentsWrapper. - TabContentsWrapper* wrapper_; - - typedef std::queue<SaveItem*> SaveItemQueue; - // A queue for items we are about to start saving. - SaveItemQueue waiting_item_queue_; - - typedef base::hash_map<int32, SaveItem*> SavedItemMap; - // saved_success_items_ is map of all saving job which are successfully saved. - SavedItemMap saved_success_items_; - - // Non-owning pointer for handling file writing on the file thread. - SaveFileManager* file_manager_; - - // We use a fake DownloadItem here in order to reuse the DownloadItemView. - // This class owns the pointer. - DownloadItem* download_; - - // The URL of the page the user wants to save. - GURL page_url_; - FilePath saved_main_file_path_; - FilePath saved_main_directory_path_; - - // The title of the page the user wants to save. - string16 title_; - - // Indicates whether the actual saving job is finishing or not. - bool finished_; - - // Indicates whether user canceled the saving job. - bool user_canceled_; - - // Indicates whether user get disk error. - bool disk_error_occurred_; - - // Type about saving page as only-html or complete-html. - SavePackageType save_type_; - - // Number of all need to be saved resources. - size_t all_save_items_count_; - - typedef base::hash_set<FilePath::StringType> FileNameSet; - // This set is used to eliminate duplicated file names in saving directory. - FileNameSet file_name_set_; - - typedef base::hash_map<FilePath::StringType, uint32> FileNameCountMap; - // This map is used to track serial number for specified filename. - FileNameCountMap file_name_count_map_; - - // Indicates current waiting state when SavePackage try to get something - // from outside. - WaitState wait_state_; - - // Since for one tab, it can only have one SavePackage in same time. - // Now we actually use render_process_id as tab's unique id. - const int tab_id_; - - // Unique ID for this SavePackage. - const int unique_id_; - - // For managing select file dialogs. - scoped_refptr<SelectFileDialog> select_file_dialog_; - - friend class SavePackageTest; - FRIEND_TEST_ALL_PREFIXES(SavePackageTest, TestSuggestedSaveNames); - FRIEND_TEST_ALL_PREFIXES(SavePackageTest, TestLongSafePureFilename); - - ScopedRunnableMethodFactory<SavePackage> method_factory_; - - DISALLOW_COPY_AND_ASSIGN(SavePackage); -}; - -#endif // CHROME_BROWSER_DOWNLOAD_SAVE_PACKAGE_H_ diff --git a/chrome/browser/download/save_package_file_picker.cc b/chrome/browser/download/save_package_file_picker.cc new file mode 100644 index 0000000..1c32aec --- /dev/null +++ b/chrome/browser/download/save_package_file_picker.cc @@ -0,0 +1,165 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/download/save_package_file_picker.h" + +#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_prefs.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/profiles/profile.h" +#include "content/browser/download/save_package.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +// If false, we don't prompt the user as to where to save the file. This +// exists only for testing. +bool g_should_prompt_for_filename = true; + +// Used for mapping between SavePackageType constants and the indexes above. +const SavePackage::SavePackageType kIndexToSaveType[] = { + SavePackage::SAVE_TYPE_UNKNOWN, + SavePackage::SAVE_AS_ONLY_HTML, + SavePackage::SAVE_AS_COMPLETE_HTML, +}; + +int SavePackageTypeToIndex(SavePackage::SavePackageType type) { + for (size_t i = 0; i < arraysize(kIndexToSaveType); ++i) { + if (kIndexToSaveType[i] == type) + return i; + } + NOTREACHED(); + return -1; +} + +// Indexes used for specifying which element in the extensions dropdown +// the user chooses when picking a save type. +const int kSelectFileHtmlOnlyIndex = 1; +const int kSelectFileCompleteIndex = 2; + +// Used for mapping between the IDS_ string identifiers and the indexes above. +const int kIndexToIDS[] = { + 0, IDS_SAVE_PAGE_DESC_HTML_ONLY, IDS_SAVE_PAGE_DESC_COMPLETE, +}; + +} + +SavePackageFilePicker::SavePackageFilePicker(SavePackage* save_package, + const FilePath& suggested_path, + bool can_save_as_complete) + : save_package_(save_package) { + // The TabContents which owns this SavePackage may have disappeared during + // the UI->FILE->UI thread hop of + // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo. + TabContents* tab_contents = save_package->tab_contents(); + if (!tab_contents) { + delete this; + return; + } + + DownloadPrefs* download_prefs = + tab_contents->profile()->GetDownloadManager()->download_prefs(); + int file_type_index = SavePackageTypeToIndex( + static_cast<SavePackage::SavePackageType>( + download_prefs->save_file_type())); + DCHECK_NE(-1, file_type_index); + + SelectFileDialog::FileTypeInfo file_type_info; + FilePath::StringType default_extension; + + // If the contents can not be saved as complete-HTML, do not show the + // file filters. + if (can_save_as_complete) { + bool add_extra_extension = false; + FilePath::StringType extra_extension; + if (!suggested_path.Extension().empty() && + suggested_path.Extension().compare(FILE_PATH_LITERAL("htm")) && + suggested_path.Extension().compare(FILE_PATH_LITERAL("html"))) { + add_extra_extension = true; + extra_extension = suggested_path.Extension().substr(1); + } + + file_type_info.extensions.resize(2); + file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( + FILE_PATH_LITERAL("htm")); + file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( + FILE_PATH_LITERAL("html")); + + if (add_extra_extension) { + file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( + extra_extension); + } + + file_type_info.extension_description_overrides.push_back( + l10n_util::GetStringUTF16(kIndexToIDS[kSelectFileCompleteIndex - 1])); + file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( + FILE_PATH_LITERAL("htm")); + file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( + FILE_PATH_LITERAL("html")); + + if (add_extra_extension) { + file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( + extra_extension); + } + + file_type_info.extension_description_overrides.push_back( + l10n_util::GetStringUTF16(kIndexToIDS[kSelectFileCompleteIndex])); + file_type_info.include_all_files = false; + default_extension = SavePackage::kDefaultHtmlExtension; + } else { + file_type_info.extensions.resize(1); + file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( + suggested_path.Extension()); + + if (!file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1][0].empty()) { + // Drop the . + file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1][0].erase(0, 1); + } + + file_type_info.include_all_files = true; + file_type_index = 1; + } + + if (g_should_prompt_for_filename) { + select_file_dialog_ = SelectFileDialog::Create(this); + select_file_dialog_->SelectFile(SelectFileDialog::SELECT_SAVEAS_FILE, + string16(), + suggested_path, + &file_type_info, + file_type_index, + default_extension, + tab_contents, + platform_util::GetTopLevel( + tab_contents->GetNativeView()), + NULL); + } else { + // Just use 'suggested_path' instead of opening the dialog prompt. + save_package_->OnPathPicked( + suggested_path, kIndexToSaveType[file_type_index]); + } +} + +SavePackageFilePicker::~SavePackageFilePicker() { +} + +void SavePackageFilePicker::SetShouldPromptUser(bool should_prompt) { + g_should_prompt_for_filename = should_prompt; +} + +void SavePackageFilePicker::FileSelected(const FilePath& path, + int index, + void* params) { + // The option index is not zero-based. + DCHECK(index >= kSelectFileHtmlOnlyIndex && + index <= kSelectFileCompleteIndex); + + save_package_->OnPathPicked(path, kIndexToSaveType[index]); + delete this; +} + +void SavePackageFilePicker::FileSelectionCanceled(void* params) { + delete this; +} diff --git a/chrome/browser/download/save_package_file_picker.h b/chrome/browser/download/save_package_file_picker.h new file mode 100644 index 0000000..638f151 --- /dev/null +++ b/chrome/browser/download/save_package_file_picker.h @@ -0,0 +1,40 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_PACKAGE_FILE_PICKER_H_ +#define CHROME_BROWSER_DOWNLOAD_SAVE_PACKAGE_FILE_PICKER_H_ +#pragma once + +#include "base/memory/ref_counted.h" +#include "chrome/browser/ui/shell_dialogs.h" + +class FilePath; +class SavePackage; + +// Handles showing a dialog to the user to ask for the filename to save a page. +class SavePackageFilePicker : public SelectFileDialog::Listener { + public: + SavePackageFilePicker(SavePackage* save_package, + const FilePath& suggested_path, + bool can_save_as_complete); + ~SavePackageFilePicker(); + + // Used to disable prompting the user for a directory/filename of the saved + // web page. This is available for testing. + static void SetShouldPromptUser(bool should_prompt); + + private: + // SelectFileDialog::Listener implementation. + virtual void FileSelected(const FilePath& path, int index, void* params); + virtual void FileSelectionCanceled(void* params); + + scoped_refptr<SavePackage> save_package_; + + // For managing select file dialogs. + scoped_refptr<SelectFileDialog> select_file_dialog_; + + DISALLOW_COPY_AND_ASSIGN(SavePackageFilePicker); +}; + +#endif // CHROME_BROWSER_DOWNLOAD_SAVE_PACKAGE_FILE_PICKER_H_ diff --git a/chrome/browser/download/save_package_unittest.cc b/chrome/browser/download/save_package_unittest.cc deleted file mode 100644 index ac250fe..0000000 --- a/chrome/browser/download/save_package_unittest.cc +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <string> - -#include "base/file_path.h" -#include "base/path_service.h" -#include "base/scoped_temp_dir.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/download/save_package.h" -#include "chrome/browser/ui/tab_contents/test_tab_contents_wrapper.h" -#include "content/browser/browser_thread.h" -#include "content/browser/net/url_request_mock_http_job.h" -#include "content/browser/tab_contents/test_tab_contents.h" -#include "googleurl/src/gurl.h" -#include "testing/gtest/include/gtest/gtest.h" - -#define FPL FILE_PATH_LITERAL -#if defined(OS_WIN) -#define HTML_EXTENSION ".htm" -// This second define is needed because MSVC is broken. -#define FPL_HTML_EXTENSION L".htm" -#else -#define HTML_EXTENSION ".html" -#define FPL_HTML_EXTENSION ".html" -#endif - -namespace { - -// This constant copied from save_package.cc. -#if defined(OS_WIN) -const uint32 kMaxFilePathLength = MAX_PATH - 1; -const uint32 kMaxFileNameLength = MAX_PATH - 1; -#elif defined(OS_POSIX) -const uint32 kMaxFilePathLength = PATH_MAX - 1; -const uint32 kMaxFileNameLength = NAME_MAX; -#endif - -// Used to make long filenames. -std::string long_file_name( - "EFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz01234567" - "89ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz012345" - "6789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz0123" - "456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789a"); - -bool HasOrdinalNumber(const FilePath::StringType& filename) { - FilePath::StringType::size_type r_paren_index = filename.rfind(FPL(')')); - FilePath::StringType::size_type l_paren_index = filename.rfind(FPL('(')); - if (l_paren_index >= r_paren_index) - return false; - - for (FilePath::StringType::size_type i = l_paren_index + 1; - i != r_paren_index; ++i) { - if (!IsAsciiDigit(filename[i])) - return false; - } - - return true; -} - -} // namespace - -class SavePackageTest : public TabContentsWrapperTestHarness { - public: - SavePackageTest() : browser_thread_(BrowserThread::UI, &message_loop_) { - } - - bool GetGeneratedFilename(bool need_success_generate_filename, - const std::string& disposition, - const std::string& url, - bool need_htm_ext, - FilePath::StringType* generated_name) { - SavePackage* save_package; - if (need_success_generate_filename) - save_package = save_package_success_.get(); - else - save_package = save_package_fail_.get(); - return save_package->GenerateFileName(disposition, GURL(url), need_htm_ext, - generated_name); - } - - FilePath EnsureHtmlExtension(const FilePath& name) { - return SavePackage::EnsureHtmlExtension(name); - } - - FilePath EnsureMimeExtension(const FilePath& name, - const std::string& content_mime_type) { - return SavePackage::EnsureMimeExtension(name, content_mime_type); - } - - GURL GetUrlToBeSaved() { - return save_package_success_->GetUrlToBeSaved(); - } - - protected: - virtual void SetUp() { - TabContentsWrapperTestHarness::SetUp(); - - // Do the initialization in SetUp so contents() is initialized by - // TabContentsWrapperTestHarness::SetUp. - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - save_package_success_ = new SavePackage(contents_wrapper(), - temp_dir_.path().AppendASCII("testfile" HTML_EXTENSION), - temp_dir_.path().AppendASCII("testfile_files")); - - // We need to construct a path that is *almost* kMaxFilePathLength long - long_file_name.resize(kMaxFilePathLength + long_file_name.length()); - while (long_file_name.length() < kMaxFilePathLength) - long_file_name += long_file_name; - long_file_name.resize( - kMaxFilePathLength - 9 - temp_dir_.path().value().length()); - - save_package_fail_ = new SavePackage(contents_wrapper(), - temp_dir_.path().AppendASCII(long_file_name + HTML_EXTENSION), - temp_dir_.path().AppendASCII(long_file_name + "_files")); - } - - private: - BrowserThread browser_thread_; - - // SavePackage for successfully generating file name. - scoped_refptr<SavePackage> save_package_success_; - // SavePackage for failed generating file name. - scoped_refptr<SavePackage> save_package_fail_; - - ScopedTempDir temp_dir_; - - DISALLOW_COPY_AND_ASSIGN(SavePackageTest); -}; - -static const struct { - const char* disposition; - const char* url; - const FilePath::CharType* expected_name; - bool need_htm_ext; -} kGeneratedFiles[] = { - // We mainly focus on testing duplicated names here, since retrieving file - // name from disposition and url has been tested in DownloadManagerTest. - - // No useful information in disposition or URL, use default. - {"1.html", "http://www.savepage.com/", - FPL("saved_resource") FPL_HTML_EXTENSION, true}, - - // No duplicate occurs. - {"filename=1.css", "http://www.savepage.com", FPL("1.css"), false}, - - // No duplicate occurs. - {"filename=1.js", "http://www.savepage.com", FPL("1.js"), false}, - - // Append numbers for duplicated names. - {"filename=1.css", "http://www.savepage.com", FPL("1(1).css"), false}, - - // No duplicate occurs. - {"filename=1(1).js", "http://www.savepage.com", FPL("1(1).js"), false}, - - // Append numbers for duplicated names. - {"filename=1.css", "http://www.savepage.com", FPL("1(2).css"), false}, - - // Change number for duplicated names. - {"filename=1(1).css", "http://www.savepage.com", FPL("1(3).css"), false}, - - // No duplicate occurs. - {"filename=1(11).css", "http://www.savepage.com", FPL("1(11).css"), false}, -}; - -TEST_F(SavePackageTest, TestSuccessfullyGenerateSavePackageFilename) { - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) { - FilePath::StringType file_name; - bool ok = GetGeneratedFilename(true, - kGeneratedFiles[i].disposition, - kGeneratedFiles[i].url, - kGeneratedFiles[i].need_htm_ext, - &file_name); - ASSERT_TRUE(ok); - EXPECT_EQ(kGeneratedFiles[i].expected_name, file_name); - } -} - -TEST_F(SavePackageTest, TestUnSuccessfullyGenerateSavePackageFilename) { - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) { - FilePath::StringType file_name; - bool ok = GetGeneratedFilename(false, - kGeneratedFiles[i].disposition, - kGeneratedFiles[i].url, - kGeneratedFiles[i].need_htm_ext, - &file_name); - ASSERT_FALSE(ok); - } -} - -// Crashing on Windows, see http://crbug.com/79365 -#if defined(OS_WIN) -#define MAYBE_TestLongSavePackageFilename DISABLED_TestLongSavePackageFilename -#else -#define MAYBE_TestLongSavePackageFilename TestLongSavePackageFilename -#endif -TEST_F(SavePackageTest, MAYBE_TestLongSavePackageFilename) { - const std::string base_url("http://www.google.com/"); - const std::string long_file = long_file_name + ".css"; - const std::string url = base_url + long_file; - - FilePath::StringType filename; - // Test that the filename is successfully shortened to fit. - ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename)); - EXPECT_TRUE(filename.length() < long_file.length()); - EXPECT_FALSE(HasOrdinalNumber(filename)); - - // Test that the filename is successfully shortened to fit, and gets an - // an ordinal appended. - ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename)); - EXPECT_TRUE(filename.length() < long_file.length()); - EXPECT_TRUE(HasOrdinalNumber(filename)); - - // Test that the filename is successfully shortened to fit, and gets a - // different ordinal appended. - FilePath::StringType filename2; - ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename2)); - EXPECT_TRUE(filename2.length() < long_file.length()); - EXPECT_TRUE(HasOrdinalNumber(filename2)); - EXPECT_NE(filename, filename2); -} - -// Crashing on Windows, see http://crbug.com/79365 -#if defined(OS_WIN) -#define MAYBE_TestLongSafePureFilename DISABLED_TestLongSafePureFilename -#else -#define MAYBE_TestLongSafePureFilename TestLongSafePureFilename -#endif -TEST_F(SavePackageTest, MAYBE_TestLongSafePureFilename) { - const FilePath save_dir(FPL("test_dir")); - const FilePath::StringType ext(FPL_HTML_EXTENSION); - FilePath::StringType filename = -#if defined(OS_WIN) - ASCIIToWide(long_file_name); -#else - long_file_name; -#endif - - // Test that the filename + extension doesn't exceed kMaxFileNameLength - uint32 max_path = SavePackage::GetMaxPathLengthForDirectory(save_dir); - ASSERT_TRUE(SavePackage::GetSafePureFileName(save_dir, ext, max_path, - &filename)); - EXPECT_TRUE(filename.length() <= kMaxFileNameLength-ext.length()); -} - -static const struct { - const FilePath::CharType* page_title; - const FilePath::CharType* expected_name; -} kExtensionTestCases[] = { - // Extension is preserved if it is already proper for HTML. - {FPL("filename.html"), FPL("filename.html")}, - {FPL("filename.HTML"), FPL("filename.HTML")}, - {FPL("filename.XHTML"), FPL("filename.XHTML")}, - {FPL("filename.xhtml"), FPL("filename.xhtml")}, - {FPL("filename.htm"), FPL("filename.htm")}, - // ".htm" is added if the extension is improper for HTML. - {FPL("hello.world"), FPL("hello.world") FPL_HTML_EXTENSION}, - {FPL("hello.txt"), FPL("hello.txt") FPL_HTML_EXTENSION}, - {FPL("is.html.good"), FPL("is.html.good") FPL_HTML_EXTENSION}, - // ".htm" is added if the name doesn't have an extension. - {FPL("helloworld"), FPL("helloworld") FPL_HTML_EXTENSION}, - {FPL("helloworld."), FPL("helloworld.") FPL_HTML_EXTENSION}, -}; - -// Crashing on Windows, see http://crbug.com/79365 -#if defined(OS_WIN) -#define MAYBE_TestEnsureHtmlExtension DISABLED_TestEnsureHtmlExtension -#else -#define MAYBE_TestEnsureHtmlExtension TestEnsureHtmlExtension -#endif -TEST_F(SavePackageTest, MAYBE_TestEnsureHtmlExtension) { - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExtensionTestCases); ++i) { - FilePath original = FilePath(kExtensionTestCases[i].page_title); - FilePath expected = FilePath(kExtensionTestCases[i].expected_name); - FilePath actual = EnsureHtmlExtension(original); - EXPECT_EQ(expected.value(), actual.value()) << "Failed for page title: " << - kExtensionTestCases[i].page_title; - } -} - -// Crashing on Windows, see http://crbug.com/79365 -#if defined(OS_WIN) -#define MAYBE_TestEnsureMimeExtension DISABLED_TestEnsureMimeExtension -#else -#define MAYBE_TestEnsureMimeExtension TestEnsureMimeExtension -#endif -TEST_F(SavePackageTest, MAYBE_TestEnsureMimeExtension) { - static const struct { - const FilePath::CharType* page_title; - const FilePath::CharType* expected_name; - const char* contents_mime_type; - } kExtensionTests[] = { - { FPL("filename.html"), FPL("filename.html"), "text/html" }, - { FPL("filename.htm"), FPL("filename.htm"), "text/html" }, - { FPL("filename.xhtml"), FPL("filename.xhtml"), "text/html" }, -#if defined(OS_WIN) - { FPL("filename"), FPL("filename.htm"), "text/html" }, -#else // defined(OS_WIN) - { FPL("filename"), FPL("filename.html"), "text/html" }, -#endif // defined(OS_WIN) - { FPL("filename.html"), FPL("filename.html"), "text/xml" }, - { FPL("filename.xml"), FPL("filename.xml"), "text/xml" }, - { FPL("filename"), FPL("filename.xml"), "text/xml" }, - { FPL("filename.xhtml"), FPL("filename.xhtml"), - "application/xhtml+xml" }, - { FPL("filename.html"), FPL("filename.html"), - "application/xhtml+xml" }, - { FPL("filename"), FPL("filename.xhtml"), "application/xhtml+xml" }, - { FPL("filename.txt"), FPL("filename.txt"), "text/plain" }, - { FPL("filename"), FPL("filename.txt"), "text/plain" }, - { FPL("filename.css"), FPL("filename.css"), "text/css" }, - { FPL("filename"), FPL("filename.css"), "text/css" }, - { FPL("filename.abc"), FPL("filename.abc"), "unknown/unknown" }, - { FPL("filename"), FPL("filename"), "unknown/unknown" }, - }; - for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(kExtensionTests); ++i) { - FilePath original = FilePath(kExtensionTests[i].page_title); - FilePath expected = FilePath(kExtensionTests[i].expected_name); - std::string mime_type(kExtensionTests[i].contents_mime_type); - FilePath actual = EnsureMimeExtension(original, mime_type); - EXPECT_EQ(expected.value(), actual.value()) << "Failed for page title: " << - kExtensionTests[i].page_title << " MIME:" << mime_type; - } -} - -// Test that the suggested names generated by SavePackage are reasonable: -// If the name is a URL, retrieve only the path component since the path name -// generation code will turn the entire URL into the file name leading to bad -// extension names. For example, a page with no title and a URL: -// http://www.foo.com/a/path/name.txt will turn into file: -// "http www.foo.com a path name.txt", when we want to save it as "name.txt". - -static const struct SuggestedSaveNameTestCase { - const char* page_url; - const string16 page_title; - const FilePath::CharType* expected_name; - bool ensure_html_extension; -} kSuggestedSaveNames[] = { - // Title overrides the URL. - { "http://foo.com", - ASCIIToUTF16("A page title"), - FPL("A page title") FPL_HTML_EXTENSION, - true - }, - // Extension is preserved. - { "http://foo.com", - ASCIIToUTF16("A page title with.ext"), - FPL("A page title with.ext"), - false - }, - // If the title matches the URL, use the last component of the URL. - { "http://foo.com/bar", - ASCIIToUTF16("http://foo.com/bar"), - FPL("bar"), - false - }, - // If the title matches the URL, but there is no "filename" component, - // use the domain. - { "http://foo.com", - ASCIIToUTF16("http://foo.com"), - FPL("foo.com"), - false - }, - // Make sure fuzzy matching works. - { "http://foo.com/bar", - ASCIIToUTF16("foo.com/bar"), - FPL("bar"), - false - }, - // A URL-like title that does not match the title is respected in full. - { "http://foo.com", - ASCIIToUTF16("http://www.foo.com/path/title.txt"), - FPL("http www.foo.com path title.txt"), - false - }, -}; - -// Crashing on Windows, see http://crbug.com/79365 -#if defined(OS_WIN) -#define MAYBE_TestSuggestedSaveNames DISABLED_TestSuggestedSaveNames -#else -#define MAYBE_TestSuggestedSaveNames TestSuggestedSaveNames -#endif -TEST_F(SavePackageTest, MAYBE_TestSuggestedSaveNames) { - for (size_t i = 0; i < arraysize(kSuggestedSaveNames); ++i) { - scoped_refptr<SavePackage> save_package( - new SavePackage(contents_wrapper(), FilePath(), FilePath())); - save_package->page_url_ = GURL(kSuggestedSaveNames[i].page_url); - save_package->title_ = kSuggestedSaveNames[i].page_title; - - FilePath save_name = save_package->GetSuggestedNameForSaveAs( - kSuggestedSaveNames[i].ensure_html_extension, - std::string()); - EXPECT_EQ(kSuggestedSaveNames[i].expected_name, save_name.value()) << - "Test case " << i; - } -} - -static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("save_page"); - -// GetUrlToBeSaved method should return correct url to be saved. -TEST_F(SavePackageTest, TestGetUrlToBeSaved) { - FilePath file_name(FILE_PATH_LITERAL("a.htm")); - GURL url = URLRequestMockHTTPJob::GetMockUrl( - FilePath(kTestDir).Append(file_name)); - NavigateAndCommit(url); - EXPECT_EQ(url, GetUrlToBeSaved()); -} - -// GetUrlToBeSaved method sould return actual url to be saved, -// instead of the displayed url used to view source of a page. -// Ex:GetUrlToBeSaved method should return http://www.google.com -// when user types view-source:http://www.google.com -TEST_F(SavePackageTest, TestGetUrlToBeSavedViewSource) { - FilePath file_name(FILE_PATH_LITERAL("a.htm")); - GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl( - FilePath(kTestDir).Append(file_name)); - GURL actual_url = URLRequestMockHTTPJob::GetMockUrl( - FilePath(kTestDir).Append(file_name)); - NavigateAndCommit(view_source_url); - EXPECT_EQ(actual_url, GetUrlToBeSaved()); - EXPECT_EQ(view_source_url, contents()->GetURL()); -} diff --git a/chrome/browser/download/save_page_uitest.cc b/chrome/browser/download/save_page_uitest.cc index 0126c6a..9f5f9cc 100644 --- a/chrome/browser/download/save_page_uitest.cc +++ b/chrome/browser/download/save_page_uitest.cc @@ -7,13 +7,13 @@ #include "base/string_util.h" #include "base/test/test_file_util.h" #include "chrome/app/chrome_command_ids.h" -#include "chrome/browser/download/save_package.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/automation/automation_proxy.h" #include "chrome/test/automation/browser_proxy.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/ui/ui_test.h" #include "chrome/test/ui_test_utils.h" +#include "content/browser/download/save_package.h" #include "content/browser/net/url_request_mock_http_job.h" #include "net/url_request/url_request_test_util.h" diff --git a/chrome/browser/download/save_types.cc b/chrome/browser/download/save_types.cc deleted file mode 100644 index d65b4d7..0000000 --- a/chrome/browser/download/save_types.cc +++ /dev/null @@ -1,31 +0,0 @@ -// 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/save_types.h" - - -SaveFileCreateInfo::SaveFileCreateInfo(const FilePath& path, - const GURL& url, - SaveFileSource save_source, - int32 save_id) - : path(path), - url(url), - save_id(save_id), - render_process_id(-1), - render_view_id(-1), - request_id(-1), - total_bytes(0), - save_source(save_source) { -} - -SaveFileCreateInfo::SaveFileCreateInfo() - : save_id(-1), - render_process_id(-1), - render_view_id(-1), - request_id(-1), - total_bytes(0), - save_source(SAVE_FILE_FROM_UNKNOWN) { -} - -SaveFileCreateInfo::~SaveFileCreateInfo() {} diff --git a/chrome/browser/download/save_types.h b/chrome/browser/download/save_types.h deleted file mode 100644 index 8295106..0000000 --- a/chrome/browser/download/save_types.h +++ /dev/null @@ -1,68 +0,0 @@ -// 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_SAVE_TYPES_H_ -#define CHROME_BROWSER_DOWNLOAD_SAVE_TYPES_H_ -#pragma once - -#include <string> -#include <utility> -#include <vector> - -#include "base/basictypes.h" -#include "base/file_path.h" -#include "googleurl/src/gurl.h" - -typedef std::vector<std::pair<int, FilePath> > FinalNameList; -typedef std::vector<int> SaveIDList; - -// This structure is used to handle and deliver some info -// when processing each save item job. -struct SaveFileCreateInfo { - enum SaveFileSource { - // This type indicates the source is not set. - SAVE_FILE_FROM_UNKNOWN = -1, - // This type indicates the save item needs to be retrieved from the network. - SAVE_FILE_FROM_NET = 0, - // This type indicates the save item needs to be retrieved from serializing - // DOM. - SAVE_FILE_FROM_DOM, - // This type indicates the save item needs to be retrieved from local file - // system. - SAVE_FILE_FROM_FILE - }; - - SaveFileCreateInfo(const FilePath& path, - const GURL& url, - SaveFileSource save_source, - int32 save_id); - - SaveFileCreateInfo(); - - ~SaveFileCreateInfo(); - - // SaveItem fields. - // The local file path of saved file. - FilePath path; - // Original URL of the saved resource. - GURL url; - // Final URL of the saved resource since some URL might be redirected. - GURL final_url; - // The unique identifier for saving job, assigned at creation by - // the SaveFileManager for its internal record keeping. - int save_id; - // IDs for looking up the tab we are associated with. - int render_process_id; - int render_view_id; - // Handle for informing the ResourceDispatcherHost of a UI based cancel. - int request_id; - // Disposition info from HTTP response. - std::string content_disposition; - // Total bytes of saved file. - int64 total_bytes; - // Source type of saved file. - SaveFileSource save_source; -}; - -#endif // CHROME_BROWSER_DOWNLOAD_SAVE_TYPES_H_ diff --git a/chrome/browser/renderer_host/DEPS b/chrome/browser/renderer_host/DEPS index 1c0609d5..549ec50 100644 --- a/chrome/browser/renderer_host/DEPS +++ b/chrome/browser/renderer_host/DEPS @@ -1,9 +1,7 @@ include_rules = [ # DO NOT ALLOW tab_contents INCLUDES FROM THIS DIRECTORY! The renderer_host # layer should be usable in contexts other than inside TabContents. Instead, - # you should call upward through the RenderViewHostDelegate interface. If - # your test needs some TabContents code, you can put it in renderer_host/test - # which can include more stuff for testing purposes. + # you should call upward through the RenderViewHostDelegate interface. # # If somebody adds an include and you're fixing the build, please revert them # instead of commenting out this rule. diff --git a/chrome/browser/renderer_host/save_file_resource_handler.cc b/chrome/browser/renderer_host/save_file_resource_handler.cc deleted file mode 100644 index 6f374b5..0000000 --- a/chrome/browser/renderer_host/save_file_resource_handler.cc +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/renderer_host/save_file_resource_handler.h" - -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/string_number_conversions.h" -#include "chrome/browser/download/save_file_manager.h" -#include "content/browser/browser_thread.h" -#include "net/base/io_buffer.h" -#include "net/url_request/url_request_status.h" - -SaveFileResourceHandler::SaveFileResourceHandler(int render_process_host_id, - int render_view_id, - const GURL& url, - SaveFileManager* manager) - : save_id_(-1), - render_process_id_(render_process_host_id), - render_view_id_(render_view_id), - url_(url), - content_length_(0), - save_manager_(manager) { -} - -bool SaveFileResourceHandler::OnUploadProgress(int request_id, - uint64 position, - uint64 size) { - return true; -} - -bool SaveFileResourceHandler::OnRequestRedirected(int request_id, - const GURL& url, - ResourceResponse* response, - bool* defer) { - final_url_ = url; - return true; -} - -bool SaveFileResourceHandler::OnResponseStarted(int request_id, - ResourceResponse* response) { - save_id_ = save_manager_->GetNextId(); - // |save_manager_| consumes (deletes): - SaveFileCreateInfo* info = new SaveFileCreateInfo; - info->url = url_; - info->final_url = final_url_; - info->total_bytes = content_length_; - info->save_id = save_id_; - info->render_process_id = render_process_id_; - info->render_view_id = render_view_id_; - info->request_id = request_id; - info->content_disposition = content_disposition_; - info->save_source = SaveFileCreateInfo::SAVE_FILE_FROM_NET; - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(save_manager_, - &SaveFileManager::StartSave, - info)); - return true; -} - -bool SaveFileResourceHandler::OnWillStart(int request_id, - const GURL& url, - bool* defer) { - return true; -} - -bool SaveFileResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf, - int* buf_size, int min_size) { - DCHECK(buf && buf_size); - if (!read_buffer_) { - *buf_size = min_size < 0 ? kReadBufSize : min_size; - read_buffer_ = new net::IOBuffer(*buf_size); - } - *buf = read_buffer_.get(); - return true; -} - -bool SaveFileResourceHandler::OnReadCompleted(int request_id, int* bytes_read) { - DCHECK(read_buffer_); - // We are passing ownership of this buffer to the save file manager. - scoped_refptr<net::IOBuffer> buffer; - read_buffer_.swap(buffer); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(save_manager_, - &SaveFileManager::UpdateSaveProgress, - save_id_, - buffer, - *bytes_read)); - return true; -} - -bool SaveFileResourceHandler::OnResponseCompleted( - int request_id, - const net::URLRequestStatus& status, - const std::string& security_info) { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(save_manager_, - &SaveFileManager::SaveFinished, - save_id_, - url_, - render_process_id_, - status.is_success() && !status.is_io_pending())); - read_buffer_ = NULL; - return true; -} - -void SaveFileResourceHandler::OnRequestClosed() { -} - -void SaveFileResourceHandler::set_content_length( - const std::string& content_length) { - base::StringToInt64(content_length, &content_length_); -} - -SaveFileResourceHandler::~SaveFileResourceHandler() {} diff --git a/chrome/browser/renderer_host/save_file_resource_handler.h b/chrome/browser/renderer_host/save_file_resource_handler.h deleted file mode 100644 index a112b33..0000000 --- a/chrome/browser/renderer_host/save_file_resource_handler.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_RENDERER_HOST_SAVE_FILE_RESOURCE_HANDLER_H_ -#define CHROME_BROWSER_RENDERER_HOST_SAVE_FILE_RESOURCE_HANDLER_H_ -#pragma once - -#include <string> - -#include "content/browser/renderer_host/resource_handler.h" -#include "googleurl/src/gurl.h" - -class SaveFileManager; - -// Forwards data to the save thread. -class SaveFileResourceHandler : public ResourceHandler { - public: - SaveFileResourceHandler(int render_process_host_id, - int render_view_id, - const GURL& url, - SaveFileManager* manager); - - // ResourceHandler Implementation: - virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size); - - // Saves the redirected URL to final_url_, we need to use the original - // URL to match original request. - virtual bool OnRequestRedirected(int request_id, const GURL& url, - ResourceResponse* response, bool* defer); - - // Sends the download creation information to the download thread. - virtual bool OnResponseStarted(int request_id, ResourceResponse* response); - - // Pass-through implementation. - virtual bool OnWillStart(int request_id, const GURL& url, bool* defer); - - // Creates a new buffer, which will be handed to the download thread for file - // writing and deletion. - virtual bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size, - int min_size); - - // Passes the buffer to the download file writer. - virtual bool OnReadCompleted(int request_id, int* bytes_read); - - virtual bool OnResponseCompleted(int request_id, - const net::URLRequestStatus& status, - const std::string& security_info); - - virtual void OnRequestClosed(); - - // If the content-length header is not present (or contains something other - // than numbers), StringToInt64 returns 0, which indicates 'unknown size' and - // is handled correctly by the SaveManager. - void set_content_length(const std::string& content_length); - - void set_content_disposition(const std::string& content_disposition) { - content_disposition_ = content_disposition; - } - - private: - virtual ~SaveFileResourceHandler(); - - int save_id_; - int render_process_id_; - int render_view_id_; - scoped_refptr<net::IOBuffer> read_buffer_; - std::string content_disposition_; - GURL url_; - GURL final_url_; - int64 content_length_; - SaveFileManager* save_manager_; - - static const int kReadBufSize = 32768; // bytes - - DISALLOW_COPY_AND_ASSIGN(SaveFileResourceHandler); -}; - -#endif // CHROME_BROWSER_RENDERER_HOST_SAVE_FILE_RESOURCE_HANDLER_H_ diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc index 0121bcd..b3d0d5e 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.cc +++ b/chrome/browser/tab_contents/render_view_context_menu.cc @@ -21,7 +21,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_util.h" -#include "chrome/browser/download/save_package.h" #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/net/browser_url_util.h" @@ -52,6 +51,7 @@ #include "chrome/common/url_constants.h" #include "content/browser/child_process_security_policy.h" #include "content/browser/debugger/devtools_window.h" +#include "content/browser/download/save_package.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/renderer_host/render_widget_host_view.h" #include "content/browser/tab_contents/navigation_entry.h" diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index f21df63..294d5d1 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc @@ -34,7 +34,6 @@ #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_started_animation.h" -#include "chrome/browser/download/save_package.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" @@ -110,6 +109,7 @@ #include "content/browser/debugger/devtools_manager.h" #include "content/browser/debugger/devtools_toggle_action.h" #include "content/browser/debugger/devtools_window.h" +#include "content/browser/download/save_package.h" #include "content/browser/host_zoom_map.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/site_instance.h" diff --git a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm index f233d5a..cdbf030 100644 --- a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm +++ b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm @@ -9,13 +9,13 @@ #import "base/memory/scoped_nsobject.h" #include "base/sys_string_conversions.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/download/save_package.h" #include "chrome/browser/sessions/restore_tab_helper.h" #include "chrome/browser/sessions/session_id.h" #include "chrome/browser/ui/cocoa/applescript/error_applescript.h" #include "chrome/browser/ui/download/download_tab_helper.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/url_constants.h" +#include "content/browser/download/save_package.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/tab_contents/navigation_controller.h" #include "content/browser/tab_contents/navigation_entry.h" diff --git a/chrome/browser/ui/download/download_tab_helper.h b/chrome/browser/ui/download/download_tab_helper.h index ac55913..e6c613c 100644 --- a/chrome/browser/ui/download/download_tab_helper.h +++ b/chrome/browser/ui/download/download_tab_helper.h @@ -7,7 +7,7 @@ #pragma once #include "base/basictypes.h" -#include "chrome/browser/download/save_package.h" +#include "content/browser/download/save_package.h" #include "content/browser/tab_contents/tab_contents_observer.h" class DownloadItem; |