summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorelijahtaylor@chromium.org <elijahtaylor@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-09 08:51:39 +0000
committerelijahtaylor@chromium.org <elijahtaylor@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-09 08:52:56 +0000
commit79141acdf19dcd33bc5cf3de516c6ed3bffc8994 (patch)
treeaa7bb366e66c0d819e27784ba23e8b735701f13c
parent5634ac560d1b61123d1b8dfb6660172d61187ffb (diff)
downloadchromium_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.cc127
-rw-r--r--chrome/browser/extensions/zipfile_installer.h61
-rw-r--r--chrome/browser/extensions/zipfile_installer_unittest.cc137
-rw-r--r--chrome/browser/resources/extensions/extensions.js6
-rw-r--r--chrome/browser/ui/webui/extensions/extension_loader_handler.cc32
-rw-r--r--chrome/browser/ui/webui/extensions/install_extension_handler.cc46
-rw-r--r--chrome/chrome_browser_extensions.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi1
-rw-r--r--chrome/common/extensions/chrome_utility_extensions_messages.h14
-rw-r--r--chrome/utility/extensions/extensions_handler.cc17
-rw-r--r--chrome/utility/extensions/extensions_handler.h1
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);