summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_provider_observers.cc3
-rw-r--r--chrome/browser/download/download_crx_util.cc4
-rw-r--r--chrome/browser/extensions/crx_installer.cc13
-rw-r--r--chrome/browser/extensions/crx_installer.h24
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc7
-rw-r--r--chrome/browser/extensions/extension_service.cc20
-rw-r--r--chrome/browser/extensions/extension_service.h6
-rw-r--r--chrome/browser/extensions/extension_webstore_private_api.cc27
-rw-r--r--chrome/browser/extensions/extension_webstore_private_api.h5
-rw-r--r--chrome/browser/extensions/extension_webstore_private_apitest.cc71
-rw-r--r--chrome/browser/extensions/webstore_inline_install_browsertest.cc4
-rw-r--r--chrome/browser/extensions/webstore_inline_installer.cc23
-rw-r--r--chrome/browser/extensions/webstore_installer.cc176
-rw-r--r--chrome/browser/extensions/webstore_installer.h78
-rw-r--r--chrome/browser/ui/webui/ntp/app_launcher_handler.cc8
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/common/chrome_notification_types.h4
17 files changed, 414 insertions, 61 deletions
diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc
index b7173cd..d9a998e 100644
--- a/chrome/browser/automation/automation_provider_observers.cc
+++ b/chrome/browser/automation/automation_provider_observers.cc
@@ -571,6 +571,8 @@ ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver(
NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
NotificationService::AllSources());
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
+ NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
@@ -607,6 +609,7 @@ void ExtensionReadyNotificationObserver::Observe(
return;
break;
case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR:
+ case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR:
case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
break;
default:
diff --git a/chrome/browser/download/download_crx_util.cc b/chrome/browser/download/download_crx_util.cc
index 1d5b4a4..f27391b 100644
--- a/chrome/browser/download/download_crx_util.cc
+++ b/chrome/browser/download/download_crx_util.cc
@@ -72,8 +72,10 @@ scoped_refptr<CrxInstaller> OpenChromeExtension(
download_item.GetURL(), download_item.referrer_url());
installer->set_original_mime_type(download_item.original_mime_type());
installer->set_apps_require_extension_mime_type(true);
- installer->set_original_url(download_item.GetURL());
+ installer->set_download_url(download_item.GetURL());
installer->set_is_gallery_install(is_gallery_download);
+ if (is_gallery_download)
+ installer->set_original_download_url(download_item.original_url());
installer->set_allow_silent_install(is_gallery_download);
installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
installer->InstallCrx(download_item.full_path());
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 9eced99..e73f4f1 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -125,6 +125,7 @@ CrxInstaller::CrxInstaller(base::WeakPtr<ExtensionService> frontend_weak,
create_app_shortcut_(false),
page_index_(-1),
frontend_weak_(frontend_weak),
+ profile_(frontend_weak->profile()),
client_(client),
apps_require_extension_mime_type_(false),
allow_silent_install_(false),
@@ -173,11 +174,11 @@ void CrxInstaller::InstallCrx(const FilePath& source_file) {
}
void CrxInstaller::InstallUserScript(const FilePath& source_file,
- const GURL& original_url) {
- DCHECK(!original_url.is_empty());
+ const GURL& download_url) {
+ DCHECK(!download_url.is_empty());
source_file_ = source_file;
- original_url_ = original_url;
+ download_url_ = download_url;
if (!BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
@@ -189,7 +190,7 @@ void CrxInstaller::InstallUserScript(const FilePath& source_file,
void CrxInstaller::ConvertUserScriptOnFileThread() {
std::string error;
scoped_refptr<Extension> extension =
- ConvertUserScriptToExtension(source_file_, original_url_, &error);
+ ConvertUserScriptToExtension(source_file_, download_url_, &error);
if (!extension) {
ReportFailureFromFileThread(error);
return;
@@ -261,7 +262,7 @@ bool CrxInstaller::AllowInstall(const Extension* extension,
// will be set. In this case, check that it was served with the
// right mime type. Make an exception for file URLs, which come
// from the users computer and have no headers.
- if (!original_url_.SchemeIsFile() &&
+ if (!download_url_.SchemeIsFile() &&
apps_require_extension_mime_type_ &&
original_mime_type_ != Extension::kMimeType) {
*error = base::StringPrintf(
@@ -288,7 +289,7 @@ bool CrxInstaller::AllowInstall(const Extension* extension,
// host (or a subdomain of the host) the download happened from. There's
// no way for us to verify that the app controls any other hosts.
URLPattern pattern(UserScript::kValidUserScriptSchemes);
- pattern.SetHost(original_url_.host());
+ pattern.SetHost(download_url_.host());
pattern.SetMatchSubdomains(true);
URLPatternSet patterns = extension_->web_extent();
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index 23ea41a..ce6bcfb 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -102,7 +102,7 @@ class CrxInstaller
// Convert the specified user script into an extension and install it.
void InstallUserScript(const FilePath& source_file,
- const GURL& original_url);
+ const GURL& download_url);
// Convert the specified web app into an extension and install it.
void InstallWebApp(const WebApplicationInfo& web_app);
@@ -111,8 +111,8 @@ class CrxInstaller
virtual void InstallUIProceed() OVERRIDE;
virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
- const GURL& original_url() const { return original_url_; }
- void set_original_url(const GURL& val) { original_url_ = val; }
+ const GURL& download_url() const { return download_url_; }
+ void set_download_url(const GURL& val) { download_url_ = val; }
Extension::Location install_source() const { return install_source_; }
void set_install_source(Extension::Location source) {
@@ -135,6 +135,14 @@ class CrxInstaller
bool is_gallery_install() const { return is_gallery_install_; }
void set_is_gallery_install(bool val) { is_gallery_install_ = val; }
+ // The original download URL should be set when the WebstoreInstaller is
+ // tracking the installation. The WebstoreInstaller uses this URL to match
+ // failure notifications to the extension.
+ const GURL& original_download_url() const { return original_download_url_; }
+ void set_original_download_url(const GURL& url) {
+ original_download_url_ = url;
+ }
+
// If |apps_require_extension_mime_type_| is set to true, be sure to set
// |original_mime_type_| as well.
void set_apps_require_extension_mime_type(
@@ -158,6 +166,8 @@ class CrxInstaller
page_index_ = page_index;
}
+ Profile* profile() { return profile_; }
+
private:
friend class ExtensionUpdaterTest;
@@ -203,7 +213,7 @@ class CrxInstaller
FilePath source_file_;
// The URL the file was downloaded from.
- GURL original_url_;
+ GURL download_url_;
// The directory extensions are installed to.
FilePath install_directory_;
@@ -235,6 +245,9 @@ class CrxInstaller
// Whether the install originated from the gallery.
bool is_gallery_install_;
+ // The download URL, before redirects, if this is a gallery install.
+ GURL original_download_url_;
+
// Whether to create an app shortcut after successful installation. This is
// set based on the user's selection in the UI and can only ever be true for
// apps.
@@ -265,6 +278,9 @@ class CrxInstaller
// The frontend we will report results back to.
base::WeakPtr<ExtensionService> frontend_weak_;
+ // The Profile where the extension is being installed in.
+ Profile* profile_;
+
// The client we will work with to do the installation. This can be NULL, in
// which case the install is silent.
// NOTE: we may be deleted on the file thread. To ensure the UI is deleted on
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 8fa5035..0121824 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -247,6 +247,8 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension(const std::string& id,
NotificationService::AllSources());
registrar.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
NotificationService::AllSources());
+ registrar.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
+ NotificationService::AllSources());
ExtensionInstallUI* install_ui = NULL;
if (ui_type == INSTALL_UI_TYPE_CANCEL)
@@ -434,6 +436,11 @@ void ExtensionBrowserTest::Observe(int type,
MessageLoopForUI::current()->Quit();
break;
+ case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR:
+ VLOG(1) << "Got EXTENSION_LOAD_ERROR notification.";
+ MessageLoopForUI::current()->Quit();
+ break;
+
case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR:
VLOG(1) << "Got EXTENSION_INSTALL_ERROR notification.";
MessageLoopForUI::current()->Quit();
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 6fe755b..ceaa22e 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -378,8 +378,7 @@ void ExtensionServiceBackend::ReportExtensionLoadError(
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (frontend_.get())
frontend_->ReportExtensionLoadError(
- extension_path, error, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
- true /* alert_on_error */);
+ extension_path, error, true /* alert_on_error */);
}
void ExtensionServiceBackend::OnLoadSingleExtension(
@@ -606,6 +605,7 @@ ExtensionService::ExtensionService(Profile* profile,
app_notification_manager_(new AppNotificationManager(profile)),
permissions_manager_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
apps_promo_(profile->GetPrefs()),
+ webstore_installer_(profile),
event_routers_initialized_(false),
extension_warnings_(profile) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -819,7 +819,7 @@ bool ExtensionService::UpdateExtension(
if (extension && extension->from_webstore())
installer->set_is_gallery_install(true);
installer->set_delete_source(true);
- installer->set_original_url(download_url);
+ installer->set_download_url(download_url);
installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
installer->InstallCrx(extension_path);
@@ -1168,11 +1168,7 @@ void ExtensionService::LoadExtensionFromCommandLine(
&error));
if (!extension) {
- ReportExtensionLoadError(
- extension_path,
- error,
- chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
- true);
+ ReportExtensionLoadError(extension_path, error, true);
return;
}
@@ -1470,10 +1466,7 @@ void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info,
}
if (!extension) {
- ReportExtensionLoadError(info.extension_path,
- error,
- chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
- false);
+ ReportExtensionLoadError(info.extension_path, error, false);
return;
}
@@ -2796,10 +2789,9 @@ void ExtensionService::OnExternalExtensionFileFound(
void ExtensionService::ReportExtensionLoadError(
const FilePath& extension_path,
const std::string &error,
- int type,
bool be_noisy) {
NotificationService* service = NotificationService::current();
- service->Notify(type,
+ service->Notify(chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
Source<Profile>(profile_),
Details<const std::string>(&error));
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 9f89a35..d59644a 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -35,6 +35,7 @@
#include "chrome/browser/extensions/external_extension_provider_interface.h"
#include "chrome/browser/extensions/pending_extension_manager.h"
#include "chrome/browser/extensions/sandboxed_extension_unpacker.h"
+#include "chrome/browser/extensions/webstore_installer.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/sync/api/sync_change.h"
#include "chrome/browser/sync/api/syncable_service.h"
@@ -206,6 +207,7 @@ class ExtensionService
const FilePath& install_directory() const { return install_directory_; }
AppsPromo* apps_promo() { return &apps_promo_; }
+ WebstoreInstaller* webstore_installer() { return &webstore_installer_; }
// Whether this extension can run in an incognito window.
virtual bool IsIncognitoEnabled(const std::string& extension_id) const;
@@ -484,7 +486,6 @@ class ExtensionService
// This method is public because ExtensionServiceBackend can post to here.
void ReportExtensionLoadError(const FilePath& extension_path,
const std::string& error,
- int type,
bool be_noisy);
// ExtensionHost of background page calls this method right after its render
@@ -787,6 +788,9 @@ class ExtensionService
// Manages the promotion of the web store.
AppsPromo apps_promo_;
+ // Coordinates the extension download and install process from the gallery.
+ WebstoreInstaller webstore_installer_;
+
// Flag to make sure event routers are only initialized once.
bool event_routers_initialized_;
diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc
index fc86aaa..151b044 100644
--- a/chrome/browser/extensions/extension_webstore_private_api.cc
+++ b/chrome/browser/extensions/extension_webstore_private_api.cc
@@ -95,6 +95,8 @@ DictionaryValue* CreateLoginResult(Profile* profile) {
return dictionary;
}
+WebstoreInstaller::Delegate* test_webstore_installer_delegate = NULL;
+
} // namespace
// static
@@ -104,6 +106,12 @@ void WebstorePrivateApi::SetTestingProfileSyncService(
}
// static
+void WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(
+ WebstoreInstaller::Delegate* delegate) {
+ test_webstore_installer_delegate = delegate;
+}
+
+// static
void BeginInstallFunction::SetIgnoreUserGestureForTests(bool ignore) {
ignore_user_gesture_for_tests = ignore;
}
@@ -361,18 +369,13 @@ bool CompleteInstallFunction::RunImpl() {
return false;
}
- GURL install_url(extension_urls::GetWebstoreInstallUrl(
- id, g_browser_process->GetApplicationLocale()));
-
- // The download url for the given |id| is now contained in |url|. We
- // navigate the current (calling) tab to this url which will result in a
- // download starting. Once completed it will go through the normal extension
- // install flow. The above call to SetWhitelistedInstallId will bypass the
- // normal permissions install dialog.
- NavigationController& controller =
- dispatcher()->delegate()->GetAssociatedTabContents()->controller();
- controller.LoadURL(install_url, source_url(), content::PAGE_TRANSITION_LINK,
- std::string());
+ // The extension will install through the normal extension install flow, but
+ // the above call to SetWhitelistedInstallId will bypass the normal
+ // permissions install dialog.
+ WebstoreInstaller* installer =
+ profile()->GetExtensionService()->webstore_installer();
+ installer->InstallExtension(
+ id, test_webstore_installer_delegate, WebstoreInstaller::FLAG_NONE);
return true;
}
diff --git a/chrome/browser/extensions/extension_webstore_private_api.h b/chrome/browser/extensions/extension_webstore_private_api.h
index 8edc6a2..23d8914b 100644
--- a/chrome/browser/extensions/extension_webstore_private_api.h
+++ b/chrome/browser/extensions/extension_webstore_private_api.h
@@ -11,6 +11,7 @@
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/webstore_install_helper.h"
+#include "chrome/browser/extensions/webstore_installer.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
@@ -22,6 +23,10 @@ class WebstorePrivateApi {
// Allows you to set the ProfileSyncService the function will use for
// testing purposes.
static void SetTestingProfileSyncService(ProfileSyncService* service);
+
+ // Allows you to override the WebstoreInstaller delegate for testing.
+ static void SetWebstoreInstallerDelegateForTesting(
+ WebstoreInstaller::Delegate* delegate);
};
// TODO(asargent): this is being deprecated in favor of
diff --git a/chrome/browser/extensions/extension_webstore_private_apitest.cc b/chrome/browser/extensions/extension_webstore_private_apitest.cc
index 90b76b2..8e0fac2 100644
--- a/chrome/browser/extensions/extension_webstore_private_apitest.cc
+++ b/chrome/browser/extensions/extension_webstore_private_apitest.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_webstore_private_api.h"
+#include "chrome/browser/extensions/webstore_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_notification_types.h"
@@ -18,6 +19,53 @@
#include "content/common/notification_service.h"
#include "net/base/mock_host_resolver.h"
+namespace {
+
+class WebstoreInstallListener : public WebstoreInstaller::Delegate {
+ public:
+ WebstoreInstallListener()
+ : received_failure_(false), received_success_(false) {}
+
+ void OnExtensionInstallSuccess(const std::string& id) OVERRIDE;
+ void OnExtensionInstallFailure(const std::string& id,
+ const std::string& error) OVERRIDE;
+ void Wait();
+
+ bool received_failure() const { return received_failure_; }
+ bool received_success() const { return received_success_; }
+ const std::string& id() const { return id_; }
+ const std::string& error() const { return error_; }
+
+ private:
+ bool received_failure_;
+ bool received_success_;
+ std::string id_;
+ std::string error_;
+};
+
+void WebstoreInstallListener::OnExtensionInstallSuccess(const std::string& id) {
+ received_success_ = true;
+ id_ = id;
+ MessageLoopForUI::current()->Quit();
+}
+
+void WebstoreInstallListener::OnExtensionInstallFailure(
+ const std::string& id, const std::string& error) {
+ received_failure_ = true;
+ id_ = id;
+ error_ = error;
+ MessageLoopForUI::current()->Quit();
+}
+
+void WebstoreInstallListener::Wait() {
+ if (received_success_ || received_failure_)
+ return;
+
+ ui_test_utils::RunMessageLoop();
+}
+
+} // namespace
+
// A base class for tests below.
class ExtensionWebstorePrivateApiTest : public ExtensionApiTest {
public:
@@ -92,27 +140,34 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallNoGesture) {
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
IncorrectManifest1) {
- ui_test_utils::WindowedNotificationObserver observer(
- chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
- NotificationService::AllSources());
+ WebstoreInstallListener listener;
+ WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener);
ASSERT_TRUE(RunInstallTest("incorrect_manifest1.html", "extension.crx"));
- observer.Wait();
+ listener.Wait();
+ ASSERT_TRUE(listener.received_failure());
+ ASSERT_EQ("Manifest file is invalid.", listener.error());
}
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
IncorrectManifest2) {
- ui_test_utils::WindowedNotificationObserver observer(
- chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
- NotificationService::AllSources());
+ WebstoreInstallListener listener;
+ WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener);
ASSERT_TRUE(RunInstallTest("incorrect_manifest2.html", "extension.crx"));
- observer.Wait();
+ listener.Wait();
+ EXPECT_TRUE(listener.received_failure());
+ ASSERT_EQ("Manifest file is invalid.", listener.error());
}
// Tests that we can request an app installed bubble (instead of the default
// UI when an app is installed).
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
AppInstallBubble) {
+ WebstoreInstallListener listener;
+ WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener);
ASSERT_TRUE(RunInstallTest("app_install_bubble.html", "app.crx"));
+ listener.Wait();
+ ASSERT_TRUE(listener.received_success());
+ ASSERT_EQ("iladmdjkfniedhfhcfoefgojhgaiaccc", listener.id());
}
// Tests using the iconUrl parameter to the install function.
diff --git a/chrome/browser/extensions/webstore_inline_install_browsertest.cc b/chrome/browser/extensions/webstore_inline_install_browsertest.cc
index f6af718..91b9ded 100644
--- a/chrome/browser/extensions/webstore_inline_install_browsertest.cc
+++ b/chrome/browser/extensions/webstore_inline_install_browsertest.cc
@@ -57,8 +57,8 @@ class WebstoreInlineInstallTest : public InProcessBrowserTest {
protected:
GURL GenerateTestServerUrl(const std::string& domain,
const std::string& page_filename) {
- GURL page_url = test_server()->GetURL(
- "files/extensions/api_test/webstore_inline_install/" + page_filename);
+ GURL page_url = test_server()->GetURL(
+ "files/extensions/api_test/webstore_inline_install/" + page_filename);
GURL::Replacements replace_host;
replace_host.SetHostStr(domain);
diff --git a/chrome/browser/extensions/webstore_inline_installer.cc b/chrome/browser/extensions/webstore_inline_installer.cc
index f5f9835..97a5aad 100644
--- a/chrome/browser/extensions/webstore_inline_installer.cc
+++ b/chrome/browser/extensions/webstore_inline_installer.cc
@@ -11,6 +11,8 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_install_dialog.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/webstore_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_utility_messages.h"
#include "chrome/common/extensions/extension.h"
@@ -375,22 +377,17 @@ void WebstoreInlineInstaller::InstallUIProceed() {
entry->use_app_installed_bubble = true;
CrxInstaller::SetWhitelistEntry(id_, entry);
- GURL install_url(extension_urls::GetWebstoreInstallUrl(
- id_, g_browser_process->GetApplicationLocale()));
+ Profile* profile = Profile::FromBrowserContext(
+ tab_contents()->browser_context());
- NavigationController& controller = tab_contents()->controller();
- // TODO(mihaip): we pretend like the referrer is the gallery in order to pass
- // the checks in ExtensionService::IsDownloadFromGallery. We should instead
- // pass the real referrer, track that this is an inline install in the
- // whitelist entry and look that up when checking that this is a valid
- // download.
- GURL referrer(extension_urls::GetWebstoreItemDetailURLPrefix() + id_);
- controller.LoadURL(install_url, referrer, content::PAGE_TRANSITION_LINK,
- std::string());
+ WebstoreInstaller* installer =
+ profile->GetExtensionService()->webstore_installer();
+ installer->InstallExtension(id_, NULL,
+ WebstoreInstaller::FLAG_OVERRIDE_REFERRER);
// TODO(mihaip): the success message should happen later, when the extension
- // is actually downloaded and installed (when NOTIFICATION_EXTENSION_INSTALLED
- // or NOTIFICATION_EXTENSION_INSTALL_ERROR fire).
+ // is actually downloaded and installed (by using the callbacks on
+ // ExtensionInstaller::Delegate).
CompleteInstall("");
}
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc
new file mode 100644
index 0000000..13f8e73
--- /dev/null
+++ b/chrome/browser/extensions/webstore_installer.cc
@@ -0,0 +1,176 @@
+// 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/extensions/webstore_installer.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/browser/tab_contents/navigation_controller.h"
+#include "content/common/notification_details.h"
+#include "content/common/notification_source.h"
+#include "googleurl/src/gurl.h"
+
+namespace {
+
+const char kInvalidIdError[] = "Invalid id";
+const char kNoBrowserError[] = "No browser found";
+
+} // namespace
+
+
+WebstoreInstaller::WebstoreInstaller(Profile* profile)
+ : profile_(profile) {
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
+ Source<Profile>(profile));
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
+ Source<CrxInstaller>(NULL));
+}
+
+WebstoreInstaller::~WebstoreInstaller() {}
+
+struct WebstoreInstaller::PendingInstall {
+ PendingInstall() : delegate(NULL) {}
+ PendingInstall(const std::string& id, const GURL& url, Delegate* delegate)
+ : id(id), download_url(url), delegate(delegate) {}
+ ~PendingInstall() {}
+
+ // The id of the extension.
+ std::string id;
+
+ // The gallery download URL for the extension.
+ GURL download_url;
+
+ // The delegate for this install.
+ Delegate* delegate;
+};
+
+void WebstoreInstaller::InstallExtension(
+ const std::string& id, Delegate* delegate, int flags) {
+ if (!Extension::IdIsValid(id)) {
+ ReportFailure(id, kInvalidIdError);
+ return;
+ }
+
+ Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
+ if (!browser) {
+ ReportFailure(id, kNoBrowserError);
+ return;
+ }
+
+ PendingInstall pending_install = CreatePendingInstall(id, delegate);
+
+ // The download url for the given |id| is now contained in
+ // |pending_install.download_url|. We navigate the current tab to this url
+ // which will result in a download starting. Once completed it will go through
+ // the normal extension install flow.
+ NavigationController& controller =
+ browser->tabstrip_model()->GetActiveTabContents()->controller();
+
+ // TODO(mihaip, jstritar): For inline installs, we pretend like the referrer
+ // is the gallery, even though this could be an inline install, in order to
+ // pass the checks in ExtensionService::IsDownloadFromGallery. We should
+ // instead pass the real referrer, track if this is an inline install in the
+ // whitelist entry and look that up when checking that this is a valid
+ // download.
+ GURL referrer = controller.GetActiveEntry()->url();
+ if (flags & FLAG_OVERRIDE_REFERRER)
+ referrer = GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id);
+
+ controller.LoadURL(pending_install.download_url,
+ referrer,
+ content::PAGE_TRANSITION_LINK,
+ std::string());
+}
+
+void WebstoreInstaller::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
+ CHECK(profile_->IsSameProfile(Source<Profile>(source).ptr()));
+ const Extension* extension = Details<const Extension>(details).ptr();
+ ReportSuccess(extension->id());
+ break;
+ }
+
+ case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
+ CrxInstaller* crx_installer = Source<CrxInstaller>(source).ptr();
+ CHECK(crx_installer);
+ if (!profile_->IsSameProfile(crx_installer->profile()))
+ return;
+
+ std::string id = GetPendingInstallId(
+ crx_installer->original_download_url());
+ const std::string* error = Details<const std::string>(details).ptr();
+ if (!id.empty())
+ ReportFailure(id, *error);
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
+}
+
+bool WebstoreInstaller::ClearPendingInstall(
+ const std::string& id, PendingInstall* install) {
+ for (size_t i = 0; i < pending_installs_.size(); ++i) {
+ if (pending_installs_[i].id == id) {
+ *install = pending_installs_[i];
+ pending_installs_.erase(pending_installs_.begin() + i);
+ return true;
+ }
+ }
+ return false;
+}
+
+const WebstoreInstaller::PendingInstall&
+ WebstoreInstaller::CreatePendingInstall(
+ const std::string& id, Delegate* delegate) {
+ GURL install_url = extension_urls::GetWebstoreInstallUrl(
+ id, g_browser_process->GetApplicationLocale());
+
+ PendingInstall pending_install(id, install_url, delegate);
+ pending_installs_.push_back(pending_install);
+
+ return *(pending_installs_.end() - 1);
+}
+
+
+std::string WebstoreInstaller::GetPendingInstallId(const GURL& url) {
+ if (url.is_empty())
+ return std::string();
+
+ for (size_t i = 0; i < pending_installs_.size(); ++i) {
+ if (pending_installs_[i].download_url == url)
+ return pending_installs_[i].id;
+ }
+
+ return std::string();
+}
+
+void WebstoreInstaller::ReportFailure(
+ const std::string& id, const std::string& error) {
+ PendingInstall install;
+ if (!ClearPendingInstall(id, &install))
+ return;
+
+ if (install.delegate)
+ install.delegate->OnExtensionInstallFailure(id, error);
+}
+
+void WebstoreInstaller::ReportSuccess(const std::string& id) {
+ PendingInstall install;
+ if (!ClearPendingInstall(id, &install))
+ return;
+
+ if (install.delegate)
+ install.delegate->OnExtensionInstallSuccess(id);
+}
diff --git a/chrome/browser/extensions/webstore_installer.h b/chrome/browser/extensions/webstore_installer.h
new file mode 100644
index 0000000..c17d4c6
--- /dev/null
+++ b/chrome/browser/extensions/webstore_installer.h
@@ -0,0 +1,78 @@
+// 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_EXTENSIONS_WEBSTORE_INSTALLER_H_
+#define CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
+
+class GURL;
+class Profile;
+
+// Downloads and installs extensions from the web store.
+class WebstoreInstaller : public NotificationObserver {
+ public:
+ enum Flag {
+ FLAG_NONE = 0,
+
+ // Sets the download's referral to the extension's page in the gallery.
+ FLAG_OVERRIDE_REFERRER = 1 << 0
+ };
+
+ class Delegate {
+ public:
+ virtual void OnExtensionInstallSuccess(const std::string& id) = 0;
+ virtual void OnExtensionInstallFailure(const std::string& id,
+ const std::string& error) = 0;
+ };
+
+ explicit WebstoreInstaller(Profile* profile);
+ virtual ~WebstoreInstaller();
+
+ // Download and install the extension with the given |id| from the Chrome
+ // Web Store. If |delegate| is not NULL, it will be notified when the
+ // install succeeds or fails.
+ // Note: the delegate should stay alive until being called back.
+ void InstallExtension(const std::string& id, Delegate* delegate, int flags);
+
+ // NotificationObserver
+ virtual void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) OVERRIDE;
+
+ private:
+ struct PendingInstall;
+
+ // Removes the PendingIntall data for the given extension, returning true and
+ // setting |install| if there is such data.
+ bool ClearPendingInstall(const std::string& id, PendingInstall* install);
+
+ // Creates the PendingInstall for the specified extension.
+ const PendingInstall& CreatePendingInstall(
+ const std::string& id, Delegate* delegate);
+
+ // Gets the extension id for the given gallery install |url|.
+ std::string GetPendingInstallId(const GURL& url);
+
+ // Reports an install |error| to the delegate for the given extension if this
+ // managed its installation. This also removes the associated PendingInstall.
+ void ReportFailure(const std::string& id, const std::string& error);
+
+ // Reports a successful install to the delegate for the given extension if
+ // this managed its installation. This also removes the associated
+ // PendingInstall.
+ void ReportSuccess(const std::string& id);
+
+ NotificationRegistrar registrar_;
+ Profile* profile_;
+ std::vector<PendingInstall> pending_installs_;
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index f3c7a10..0524367 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -371,6 +371,12 @@ void AppLauncherHandler::Observe(int type,
break;
}
case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
+ CrxInstaller* crx_installer = Source<CrxInstaller>(source).ptr();
+ if (!Profile::FromWebUI(web_ui_)->IsSameProfile(crx_installer->profile()))
+ return;
+ // Fall Through.
+ }
+ case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR: {
attempted_bookmark_app_install_ = false;
break;
}
@@ -536,6 +542,8 @@ void AppLauncherHandler::HandleGetApps(const ListValue* args) {
registrar_.Add(this, chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED,
Source<Profile>(profile));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
+ Source<CrxInstaller>(NULL));
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
Source<Profile>(profile));
}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 9ce4001..6190361 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1233,6 +1233,8 @@
'browser/extensions/webstore_inline_installer.h',
'browser/extensions/webstore_install_helper.cc',
'browser/extensions/webstore_install_helper.h',
+ 'browser/extensions/webstore_installer.cc',
+ 'browser/extensions/webstore_installer.h',
'browser/external_protocol/external_protocol_handler.cc',
'browser/external_protocol/external_protocol_handler.h',
'browser/external_protocol/external_protocol_observer.cc',
diff --git a/chrome/common/chrome_notification_types.h b/chrome/common/chrome_notification_types.h
index c6357b0..515c6ed 100644
--- a/chrome/common/chrome_notification_types.h
+++ b/chrome/common/chrome_notification_types.h
@@ -367,6 +367,10 @@ enum NotificationType {
// the source is a Profile.
NOTIFICATION_EXTENSION_LOADED,
+ // An error occured while attempting to load an extension. The details are a
+ // string with details about why the load failed.
+ NOTIFICATION_EXTENSION_LOAD_ERROR,
+
// Sent when attempting to load a new extension, but they are disabled. The
// details are an Extension*, and the source is a Profile*.
NOTIFICATION_EXTENSION_UPDATE_DISABLED,