diff options
author | elijahtaylor@chromium.org <elijahtaylor@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-09 08:51:39 +0000 |
---|---|---|
committer | elijahtaylor@chromium.org <elijahtaylor@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-09 08:52:56 +0000 |
commit | 79141acdf19dcd33bc5cf3de516c6ed3bffc8994 (patch) | |
tree | aa7bb366e66c0d819e27784ba23e8b735701f13c | |
parent | 5634ac560d1b61123d1b8dfb6660172d61187ffb (diff) | |
download | chromium_src-79141acdf19dcd33bc5cf3de516c6ed3bffc8994.zip chromium_src-79141acdf19dcd33bc5cf3de516c6ed3bffc8994.tar.gz chromium_src-79141acdf19dcd33bc5cf3de516c6ed3bffc8994.tar.bz2 |
Allow drag-and-drop of zipped extensions on chrome://extensions
TEST=drag zip file extension to chrome://extensions
BUG=395311
Review URL: https://codereview.chromium.org/406713002
Cr-Commit-Position: refs/heads/master@{#288545}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288545 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/extensions/zipfile_installer.cc | 127 | ||||
-rw-r--r-- | chrome/browser/extensions/zipfile_installer.h | 61 | ||||
-rw-r--r-- | chrome/browser/extensions/zipfile_installer_unittest.cc | 137 | ||||
-rw-r--r-- | chrome/browser/resources/extensions/extensions.js | 6 | ||||
-rw-r--r-- | chrome/browser/ui/webui/extensions/extension_loader_handler.cc | 32 | ||||
-rw-r--r-- | chrome/browser/ui/webui/extensions/install_extension_handler.cc | 46 | ||||
-rw-r--r-- | chrome/chrome_browser_extensions.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests_unit.gypi | 1 | ||||
-rw-r--r-- | chrome/common/extensions/chrome_utility_extensions_messages.h | 14 | ||||
-rw-r--r-- | chrome/utility/extensions/extensions_handler.cc | 17 | ||||
-rw-r--r-- | chrome/utility/extensions/extensions_handler.h | 1 |
11 files changed, 413 insertions, 31 deletions
diff --git a/chrome/browser/extensions/zipfile_installer.cc b/chrome/browser/extensions/zipfile_installer.cc new file mode 100644 index 0000000..edf03175 --- /dev/null +++ b/chrome/browser/extensions/zipfile_installer.cc @@ -0,0 +1,127 @@ +// Copyright 2014 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/extensions/zipfile_installer.h" + +#include "base/file_util.h" +#include "base/path_service.h" +#include "chrome/browser/extensions/extension_error_reporter.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/unpacked_installer.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/extensions/chrome_utility_extensions_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/utility_process_host.h" + +using content::BrowserThread; +using content::UtilityProcessHost; + +namespace { + +const char kExtensionHandlerTempDirError[] = + "Could not create temporary directory for zipped extension."; + +} // namespace + +namespace extensions { + +ZipFileInstaller::ZipFileInstaller(ExtensionService* extension_service) + : be_noisy_on_failure_(true), + extension_service_weak_(extension_service->AsWeakPtr()) { +} + +void ZipFileInstaller::LoadFromZipFile(const base::FilePath& path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + zip_path_ = path; + BrowserThread::PostTask(BrowserThread::FILE, + FROM_HERE, + base::Bind(&ZipFileInstaller::PrepareTempDir, this)); +} + +void ZipFileInstaller::PrepareTempDir() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + base::FilePath temp_dir; + PathService::Get(base::DIR_TEMP, &temp_dir); + base::FilePath new_temp_dir; + if (!base::CreateTemporaryDirInDir( + temp_dir, + zip_path_.RemoveExtension().BaseName().value() + + FILE_PATH_LITERAL("_"), + &new_temp_dir)) { + OnUnzipFailed(std::string(kExtensionHandlerTempDirError)); + return; + } + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&ZipFileInstaller::StartWorkOnIOThread, this, new_temp_dir)); +} + +ZipFileInstaller::~ZipFileInstaller() { +} + +// static +scoped_refptr<ZipFileInstaller> ZipFileInstaller::Create( + ExtensionService* extension_service) { + DCHECK(extension_service); + return scoped_refptr<ZipFileInstaller>( + new ZipFileInstaller(extension_service)); +} + +void ZipFileInstaller::StartWorkOnIOThread(const base::FilePath& temp_dir) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + UtilityProcessHost* host = + UtilityProcessHost::Create(this, base::MessageLoopProxy::current().get()); + host->SetExposedDir(temp_dir); + host->Send(new ChromeUtilityMsg_UnzipToDir(zip_path_, temp_dir)); +} + +void ZipFileInstaller::ReportSuccessOnUIThread( + const base::FilePath& unzipped_path) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (extension_service_weak_.get()) + UnpackedInstaller::Create(extension_service_weak_.get()) + ->Load(unzipped_path); +} + +void ZipFileInstaller::ReportErrorOnUIThread(const std::string& error) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (extension_service_weak_.get()) { + ExtensionErrorReporter::GetInstance()->ReportLoadError( + zip_path_, + error, + extension_service_weak_->profile(), + be_noisy_on_failure_); + } +} + +void ZipFileInstaller::OnUnzipSucceeded(const base::FilePath& unzipped_path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind( + &ZipFileInstaller::ReportSuccessOnUIThread, this, unzipped_path)); +} + +void ZipFileInstaller::OnUnzipFailed(const std::string& error) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&ZipFileInstaller::ReportErrorOnUIThread, this, error)); +} + +bool ZipFileInstaller::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ZipFileInstaller, message) + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnzipToDir_Succeeded, + OnUnzipSucceeded) + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnzipToDir_Failed, OnUnzipFailed) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +} // namespace extensions diff --git a/chrome/browser/extensions/zipfile_installer.h b/chrome/browser/extensions/zipfile_installer.h new file mode 100644 index 0000000..e6d39d9 --- /dev/null +++ b/chrome/browser/extensions/zipfile_installer.h @@ -0,0 +1,61 @@ +// Copyright 2014 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_EXTENSIONS_ZIPFILE_INSTALLER_H_ +#define CHROME_BROWSER_EXTENSIONS_ZIPFILE_INSTALLER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "content/public/browser/utility_process_host_client.h" + +class ExtensionService; + +namespace IPC { +class Message; +} + +namespace extensions { + +// ZipFileInstaller unzips an extension that is zipped up via a utility process. +// The contents are then loaded via UnpackedInstaller. +class ZipFileInstaller : public content::UtilityProcessHostClient { + public: + static scoped_refptr<ZipFileInstaller> Create( + ExtensionService* extension_service); + + void LoadFromZipFile(const base::FilePath& path); + + void set_be_noisy_on_failure(bool value) { be_noisy_on_failure_ = value; } + + // UtilityProcessHostClient + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + private: + explicit ZipFileInstaller(ExtensionService* extension_service); + virtual ~ZipFileInstaller(); + + void PrepareTempDir(); + void StartWorkOnIOThread(const base::FilePath& temp_dir); + void ReportSuccessOnUIThread(const base::FilePath& unzipped_path); + void ReportErrorOnUIThread(const std::string& error); + + void OnUnzipSucceeded(const base::FilePath& unzipped_path); + void OnUnzipFailed(const std::string& error); + + bool be_noisy_on_failure_; + base::WeakPtr<ExtensionService> extension_service_weak_; + base::FilePath zip_path_; + + DISALLOW_COPY_AND_ASSIGN(ZipFileInstaller); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_ZIPFILE_INSTALLER_H_ diff --git a/chrome/browser/extensions/zipfile_installer_unittest.cc b/chrome/browser/extensions/zipfile_installer_unittest.cc new file mode 100644 index 0000000..63ea3c7 --- /dev/null +++ b/chrome/browser/extensions/zipfile_installer_unittest.cc @@ -0,0 +1,137 @@ +// Copyright 2014 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/bind.h" +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/strings/string_util.h" +#include "base/values.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/test_extension_system.h" +#include "chrome/browser/extensions/zipfile_installer.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "content/public/test/test_utils.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/extension_registry_observer.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/login/users/user_manager.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" +#endif + +namespace extensions { + +namespace { + +struct MockExtensionRegistryObserver : public ExtensionRegistryObserver { + void WaitForInstall() { + scoped_refptr<content::MessageLoopRunner> runner = + new content::MessageLoopRunner; + quit_closure_ = runner->QuitClosure(); + runner->Run(); + } + + virtual void OnExtensionWillBeInstalled( + content::BrowserContext* browser_context, + const Extension* extension, + bool is_update, + bool from_ephemeral, + const std::string& old_name) OVERRIDE { + last_extension_installed = extension->id(); + quit_closure_.Run(); + } + + std::string last_extension_installed; + base::Closure quit_closure_; +}; + +} // namespace + +class ZipFileInstallerTest : public testing::Test { + public: + ZipFileInstallerTest() + : browser_threads_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} + + virtual void SetUp() { + in_process_utility_thread_helper_.reset( + new content::InProcessUtilityThreadHelper); + + // Create profile for extension service. + profile_.reset(new TestingProfile()); + TestExtensionSystem* system = + static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile_.get())); + extension_service_ = system->CreateExtensionService( + base::CommandLine::ForCurrentProcess(), base::FilePath(), false); + ExtensionRegistry* registry(ExtensionRegistry::Get(profile_.get())); + registry->AddObserver(&observer_); + } + + virtual void TearDown() { + // Need to destruct ZipFileInstaller before the message loop since + // it posts a task to it. + zipfile_installer_ = NULL; + ExtensionRegistry* registry(ExtensionRegistry::Get(profile_.get())); + registry->RemoveObserver(&observer_); + profile_.reset(); + base::RunLoop().RunUntilIdle(); + } + + void RunInstaller(const std::string& zip_name) { + base::FilePath original_path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &original_path)); + original_path = original_path.AppendASCII("extensions") + .AppendASCII("zipfile_installer") + .AppendASCII(zip_name); + ASSERT_TRUE(base::PathExists(original_path)) << original_path.value(); + + zipfile_installer_ = ZipFileInstaller::Create(extension_service_); + + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, + base::Bind(&ZipFileInstaller::LoadFromZipFile, + zipfile_installer_.get(), + original_path)); + observer_.WaitForInstall(); + } + + protected: + scoped_refptr<ZipFileInstaller> zipfile_installer_; + + scoped_ptr<TestingProfile> profile_; + ExtensionService* extension_service_; + + content::TestBrowserThreadBundle browser_threads_; + scoped_ptr<content::InProcessUtilityThreadHelper> + in_process_utility_thread_helper_; + MockExtensionRegistryObserver observer_; + +#if defined(OS_CHROMEOS) + chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; + chromeos::ScopedTestCrosSettings test_cros_settings_; + // ChromeOS needs a user manager to instantiate an extension service. + chromeos::ScopedTestUserManager test_user_manager_; +#endif +}; + +TEST_F(ZipFileInstallerTest, GoodZip) { + RunInstaller("good.zip"); +} + +TEST_F(ZipFileInstallerTest, ZipWithPublicKey) { + RunInstaller("public_key.zip"); + const char kIdForPublicKey[] = "ikppjpenhoddphklkpdfdfdabbakkpal"; + EXPECT_EQ(observer_.last_extension_installed, kIdForPublicKey); +} + +} // namespace extensions diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js index fa1386e..e678099 100644 --- a/chrome/browser/resources/extensions/extensions.js +++ b/chrome/browser/resources/extensions/extensions.js @@ -66,8 +66,10 @@ cr.define('extensions', function() { } // Only process files that look like extensions. Other files should // navigate the browser normally. - if (!toSend && /\.(crx|user\.js)$/i.test(e.dataTransfer.files[0].name)) + if (!toSend && + /\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) { toSend = 'installDroppedFile'; + } if (toSend) { e.preventDefault(); @@ -430,7 +432,7 @@ cr.define('extensions', function() { ' min-width: ' + pxWidth + 'px;' + '}'; document.querySelector('head').appendChild(style); - } + }; // Export return { diff --git a/chrome/browser/ui/webui/extensions/extension_loader_handler.cc b/chrome/browser/ui/webui/extensions/extension_loader_handler.cc index 4f87543..72906fc 100644 --- a/chrome/browser/ui/webui/extensions/extension_loader_handler.cc +++ b/chrome/browser/ui/webui/extensions/extension_loader_handler.cc @@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/path_util.h" #include "chrome/browser/extensions/unpacked_installer.h" +#include "chrome/browser/extensions/zipfile_installer.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/chrome_select_file_policy.h" #include "content/public/browser/browser_thread.h" @@ -218,14 +219,27 @@ void ExtensionLoaderHandler::HandleDisplayFailures( void ExtensionLoaderHandler::LoadUnpackedExtensionImpl( const base::FilePath& file_path) { - scoped_refptr<UnpackedInstaller> installer = UnpackedInstaller::Create( - ExtensionSystem::Get(profile_)->extension_service()); - - // We do our own error handling, so we don't want a load failure to trigger - // a dialog. - installer->set_be_noisy_on_failure(false); - - installer->Load(file_path); + if (EndsWith(file_path.AsUTF16Unsafe(), + base::ASCIIToUTF16(".zip"), + false /* case insensitive */)) { + scoped_refptr<ZipFileInstaller> installer = ZipFileInstaller::Create( + ExtensionSystem::Get(profile_)->extension_service()); + + // We do our own error handling, so we don't want a load failure to trigger + // a dialog. + installer->set_be_noisy_on_failure(false); + + installer->LoadFromZipFile(file_path); + } else { + scoped_refptr<UnpackedInstaller> installer = UnpackedInstaller::Create( + ExtensionSystem::Get(profile_)->extension_service()); + + // We do our own error handling, so we don't want a load failure to trigger + // a dialog. + installer->set_be_noisy_on_failure(false); + + installer->Load(file_path); + } } void ExtensionLoaderHandler::OnLoadFailure( @@ -290,7 +304,7 @@ void ExtensionLoaderHandler::AddFailure( scoped_ptr<base::DictionaryValue> failure(new base::DictionaryValue()); failure->Set("path", new base::StringValue(prettified_path.LossyDisplayName())); - failure->Set("error", new base::StringValue(base::UTF8ToUTF16(error))); + failure->Set("reason", new base::StringValue(base::UTF8ToUTF16(error))); failure->Set("manifest", manifest_value.release()); failures_.Append(failure.release()); diff --git a/chrome/browser/ui/webui/extensions/install_extension_handler.cc b/chrome/browser/ui/webui/extensions/install_extension_handler.cc index b0770b8..b54dafc 100644 --- a/chrome/browser/ui/webui/extensions/install_extension_handler.cc +++ b/chrome/browser/ui/webui/extensions/install_extension_handler.cc @@ -11,6 +11,7 @@ #include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/unpacked_installer.h" +#include "chrome/browser/extensions/zipfile_installer.h" #include "chrome/browser/profiles/profile.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" @@ -99,30 +100,35 @@ void InstallExtensionHandler::HandleInstallMessage( Profile* profile = Profile::FromBrowserContext( web_ui()->GetWebContents()->GetBrowserContext()); - scoped_ptr<ExtensionInstallPrompt> prompt( - new ExtensionInstallPrompt(web_ui()->GetWebContents())); - scoped_refptr<CrxInstaller> crx_installer(CrxInstaller::Create( - ExtensionSystem::Get(profile)->extension_service(), - prompt.Pass())); - crx_installer->set_error_on_unsupported_requirements(true); - crx_installer->set_off_store_install_allow_reason( - CrxInstaller::OffStoreInstallAllowedFromSettingsPage); - crx_installer->set_install_immediately(true); const bool kCaseSensitive = false; - if (EndsWith(file_display_name_, - base::ASCIIToUTF16(".user.js"), - kCaseSensitive)) { - crx_installer->InstallUserScript( - file_to_install_, - net::FilePathToFileURL(file_to_install_)); - } else if (EndsWith(file_display_name_, - base::ASCIIToUTF16(".crx"), - kCaseSensitive)) { - crx_installer->InstallCrx(file_to_install_); + if (EndsWith( + file_display_name_, base::ASCIIToUTF16(".zip"), kCaseSensitive)) { + ZipFileInstaller::Create(ExtensionSystem::Get(profile)->extension_service()) + ->LoadFromZipFile(file_to_install_); } else { - CHECK(false); + scoped_ptr<ExtensionInstallPrompt> prompt( + new ExtensionInstallPrompt(web_ui()->GetWebContents())); + scoped_refptr<CrxInstaller> crx_installer(CrxInstaller::Create( + ExtensionSystem::Get(profile)->extension_service(), prompt.Pass())); + crx_installer->set_error_on_unsupported_requirements(true); + crx_installer->set_off_store_install_allow_reason( + CrxInstaller::OffStoreInstallAllowedFromSettingsPage); + crx_installer->set_install_immediately(true); + + if (EndsWith(file_display_name_, + base::ASCIIToUTF16(".user.js"), + kCaseSensitive)) { + crx_installer->InstallUserScript( + file_to_install_, net::FilePathToFileURL(file_to_install_)); + } else if (EndsWith(file_display_name_, + base::ASCIIToUTF16(".crx"), + kCaseSensitive)) { + crx_installer->InstallCrx(file_to_install_); + } else { + CHECK(false); + } } file_to_install_.clear(); diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index a8b3149..fa43384 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -905,6 +905,8 @@ 'browser/extensions/window_controller_list.cc', 'browser/extensions/window_controller_list.h', 'browser/extensions/window_controller_list_observer.h', + 'browser/extensions/zipfile_installer.cc', + 'browser/extensions/zipfile_installer.h', ], 'chrome_browser_extensions_app_list_sources': [ 'browser/apps/drive/drive_app_converter.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 50051de..994bfa0 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -981,6 +981,7 @@ 'browser/extensions/user_script_master_unittest.cc', 'browser/extensions/webstore_inline_installer_unittest.cc', 'browser/extensions/webstore_installer_unittest.cc', + 'browser/extensions/zipfile_installer_unittest.cc', 'browser/external_protocol/external_protocol_handler_unittest.cc', 'browser/favicon/favicon_handler_unittest.cc', 'browser/file_select_helper_unittest.cc', diff --git a/chrome/common/extensions/chrome_utility_extensions_messages.h b/chrome/common/extensions/chrome_utility_extensions_messages.h index 7d6053f..e2881cd 100644 --- a/chrome/common/extensions/chrome_utility_extensions_messages.h +++ b/chrome/common/extensions/chrome_utility_extensions_messages.h @@ -99,6 +99,10 @@ IPC_MESSAGE_CONTROL4(ChromeUtilityMsg_UnpackExtension, int /* Manifest::Location */, int /* InitFromValue flags */) +IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_UnzipToDir, + base::FilePath /* zip_file */, + base::FilePath /* dir */) + // Tell the utility process to parse the given xml document. IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_ParseUpdateManifest, std::string /* xml document contents */) @@ -199,6 +203,16 @@ IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_UnpackExtension_Succeeded, IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_UnpackExtension_Failed, base::string16 /* error_message, if any */) +// Reply when the utility process is done unzipping a file. |unpacked_path| +// is the directory which contains the unzipped contents. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_UnzipToDir_Succeeded, + base::FilePath /* unpacked_path */) + +// Reply when the utility process failed to unzip a file. |error| contains +// an error string to be reported to the user. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_UnzipToDir_Failed, + std::string /* error */) + // Reply when the utility process has succeeded in parsing an update manifest // xml document. IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded, diff --git a/chrome/utility/extensions/extensions_handler.cc b/chrome/utility/extensions/extensions_handler.cc index 6aa0c2e..25f65a7 100644 --- a/chrome/utility/extensions/extensions_handler.cc +++ b/chrome/utility/extensions/extensions_handler.cc @@ -21,6 +21,7 @@ #include "extensions/common/update_manifest.h" #include "media/base/media.h" #include "media/base/media_file_checker.h" +#include "third_party/zlib/google/zip.h" #include "ui/base/ui_base_switches.h" #if defined(OS_WIN) @@ -52,6 +53,9 @@ void ReleaseProcessIfNeeded() { content::UtilityThread::Get()->ReleaseProcessIfNeeded(); } +const char kExtensionHandlerUnzipError[] = + "Could not unzip extension for install."; + } // namespace ExtensionsHandler::ExtensionsHandler() {} @@ -81,6 +85,7 @@ bool ExtensionsHandler::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ExtensionsHandler, message) IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackExtension, OnUnpackExtension) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnzipToDir, OnUnzipToDir) IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseUpdateManifest, OnParseUpdateManifest) IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImageBase64, OnDecodeImageBase64) @@ -139,6 +144,18 @@ void ExtensionsHandler::OnUnpackExtension( ReleaseProcessIfNeeded(); } +void ExtensionsHandler::OnUnzipToDir(const base::FilePath& zip_path, + const base::FilePath& dir) { + if (!zip::Unzip(zip_path, dir)) { + Send(new ChromeUtilityHostMsg_UnzipToDir_Failed( + std::string(kExtensionHandlerUnzipError))); + } else { + Send(new ChromeUtilityHostMsg_UnzipToDir_Succeeded(dir)); + } + + ReleaseProcessIfNeeded(); +} + void ExtensionsHandler::OnParseUpdateManifest(const std::string& xml) { UpdateManifest manifest; if (!manifest.Parse(xml)) { diff --git a/chrome/utility/extensions/extensions_handler.h b/chrome/utility/extensions/extensions_handler.h index 3fc732b..bc06a100 100644 --- a/chrome/utility/extensions/extensions_handler.h +++ b/chrome/utility/extensions/extensions_handler.h @@ -39,6 +39,7 @@ class ExtensionsHandler : public UtilityMessageHandler { void OnUnpackExtension(const base::FilePath& extension_path, const std::string& extension_id, int location, int creation_flags); + void OnUnzipToDir(const base::FilePath& zip_path, const base::FilePath& dir); void OnParseUpdateManifest(const std::string& xml); void OnDecodeImageBase64(const std::string& encoded_data); void OnParseJSON(const std::string& json); |