Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(283)

Unified Diff: chrome/browser/extensions/webstore_inline_installer.cc

Issue 7741037: Add WebstoreInlineInstaller (downloads store data, shows the install UI, and starts the install). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Put webstore response in the right directory. Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/extensions/webstore_inline_installer.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/extensions/webstore_inline_installer.cc
diff --git a/chrome/browser/extensions/webstore_inline_installer.cc b/chrome/browser/extensions/webstore_inline_installer.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f13c94f400b5f4ce7c60d432e982354815caf4cb
--- /dev/null
+++ b/chrome/browser/extensions/webstore_inline_installer.cc
@@ -0,0 +1,293 @@
+// 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_inline_installer.h"
+
+#include <vector>
+
+#include "base/string_util.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/extension_install_dialog.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_utility_messages.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/browser/utility_process_host.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/escape.h"
+#include "net/url_request/url_request_status.h"
+
+const char kManifestKey[] = "manifest";
+const char kIconUrlKey[] = "icon_url";
+const char kLocalizedNameKey[] = "localized_name";
+
+const char kInvalidWebstoreItemId[] = "Invalid webstore item ID";
+const char kWebstoreRequestError[] = "Could not fetch data from webstore";
+const char kInvalidWebstoreResponseError[] = "Invalid webstore reponse";
+const char kInvalidManifestError[] = "Invalid manifest";
+const char kUserCancelledError[] = "User cancelled install";
+
+class SafeWebstoreResponseParser : public UtilityProcessHost::Client {
+ public:
+ SafeWebstoreResponseParser(WebstoreInlineInstaller *client,
+ const std::string& webstore_data)
+ : client_(client),
+ webstore_data_(webstore_data),
+ utility_host_(NULL) {}
+
+ void Start() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &SafeWebstoreResponseParser::StartWorkOnIOThread));
+ }
+
+ void StartWorkOnIOThread() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ utility_host_ = new UtilityProcessHost(this, BrowserThread::IO);
+ utility_host_->Send(new ChromeUtilityMsg_ParseJSON(webstore_data_));
+ }
+
+ // Implementing pieces of the UtilityProcessHost::Client interface.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(SafeWebstoreResponseParser, message)
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
+ OnJSONParseSucceeded)
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
+ OnJSONParseFailed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+ }
+
+ void OnJSONParseSucceeded(const ListValue& wrapper) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ Value* value = NULL;
+ CHECK(wrapper.Get(0, &value));
+ if (value->IsType(Value::TYPE_DICTIONARY)) {
+ parsed_webstore_data_.reset(
+ static_cast<DictionaryValue*>(value)->DeepCopy());
+ } else {
+ error_ = kInvalidWebstoreResponseError;
+ }
+
+ ReportResults();
+ }
+
+ virtual void OnJSONParseFailed(const std::string& error_message) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ error_ = error_message;
+ ReportResults();
+ }
+
+ void ReportResults() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // The utility_host_ will take care of deleting itself after this call.
+ utility_host_ = NULL;
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &SafeWebstoreResponseParser::ReportResultOnUIThread));
+ }
+
+ void ReportResultOnUIThread() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (error_.empty() && parsed_webstore_data_.get()) {
+ client_->OnWebstoreResponseParseSuccess(parsed_webstore_data_.release());
+ } else {
+ client_->OnWebstoreResponseParseFailure(error_);
+ }
+ }
+
+ private:
+ virtual ~SafeWebstoreResponseParser() {}
+
+ WebstoreInlineInstaller* client_;
+
+ std::string webstore_data_;
+
+ UtilityProcessHost* utility_host_;
+
+ std::string error_;
+ scoped_ptr<DictionaryValue> parsed_webstore_data_;
+};
+
+WebstoreInlineInstaller::WebstoreInlineInstaller(TabContents* tab_contents,
+ std::string webstore_item_id,
+ Delegate* delegate)
+ : tab_contents_(tab_contents),
+ id_(webstore_item_id),
+ delegate_(delegate) {}
+
+WebstoreInlineInstaller::~WebstoreInlineInstaller() {
+}
+
+void WebstoreInlineInstaller::BeginInstall() {
+ AddRef(); // Balanced in CompleteInstall.
+
+ if (!Extension::IdIsValid(id_)) {
+ CompleteInstall(kInvalidWebstoreItemId);
+ return;
+ }
+
+ GURL webstore_data_url(extension_urls::GetWebstoreItemJsonDataURL(id_));
+
+ webstore_data_url_fetcher_.reset(
+ new URLFetcher(webstore_data_url, URLFetcher::GET, this));
+ Profile* profile = Profile::FromBrowserContext(
+ tab_contents_->browser_context());
+ webstore_data_url_fetcher_->set_request_context(
+ profile->GetRequestContext());
+ webstore_data_url_fetcher_->Start();
+}
+
+void WebstoreInlineInstaller::OnURLFetchComplete(const URLFetcher* source) {
+ CHECK_EQ(webstore_data_url_fetcher_.get(), source);
+
+ if (!webstore_data_url_fetcher_->status().is_success() ||
+ webstore_data_url_fetcher_->response_code() != 200) {
+ CompleteInstall(kWebstoreRequestError);
+ return;
+ }
+
+ std::string webstore_json_data;
+ webstore_data_url_fetcher_->GetResponseAsString(&webstore_json_data);
+ webstore_data_url_fetcher_.reset();
+
+ scoped_refptr<SafeWebstoreResponseParser> parser =
+ new SafeWebstoreResponseParser(this, webstore_json_data);
+ // The parser will call us back via OnWebstoreResponseParseSucces or
+ // OnWebstoreResponseParseFailure.
+ parser->Start();
+}
+
+void WebstoreInlineInstaller::OnWebstoreResponseParseSuccess(
+ DictionaryValue* webstore_data) {
+ webstore_data_.reset(webstore_data);
+
+ std::string manifest;
+ if (!webstore_data->GetString(kManifestKey, &manifest)) {
+ CompleteInstall(kInvalidWebstoreResponseError);
+ return;
+ }
+
+ // Localized name is optional.
+ if (webstore_data->HasKey(kLocalizedNameKey) &&
+ !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) {
+ CompleteInstall(kInvalidWebstoreResponseError);
+ return;
+ }
+
+ // Icon URL is optional.
+ GURL icon_url;
+ if (webstore_data->HasKey(kIconUrlKey)) {
+ std::string icon_url_string;
+ if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
+ CompleteInstall(kInvalidWebstoreResponseError);
+ return;
+ }
+ icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
+ icon_url_string);
+ if (!icon_url.is_valid()) {
+ CompleteInstall(kInvalidWebstoreResponseError);
+ return;
+ }
+ }
+
+ scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
+ this,
+ manifest,
+ "", // We don't have any icon data.
+ icon_url,
+ Profile::FromBrowserContext(tab_contents_->browser_context())->
+ GetRequestContext());
+ // The helper will call us back via OnWebstoreParseSucces or
+ // OnWebstoreParseFailure.
+ helper->Start();
+}
+
+void WebstoreInlineInstaller::OnWebstoreResponseParseFailure(
+ const std::string& error) {
+ CompleteInstall(error);
+}
+
+void WebstoreInlineInstaller::OnWebstoreParseSuccess(
+ const SkBitmap& icon,
+ base::DictionaryValue* manifest) {
+ manifest_.reset(manifest);
+ icon_ = icon;
+
+ Profile* profile = Profile::FromBrowserContext(
+ tab_contents_->browser_context());
+ scoped_refptr<Extension> dummy_extension;
+ ShowExtensionInstallDialogForManifest(profile,
+ this,
+ manifest,
+ id_,
+ localized_name_,
+ &icon_,
+ ExtensionInstallUI::INSTALL_PROMPT,
+ &dummy_extension);
+
+ if (!dummy_extension.get()) {
+ CompleteInstall(kInvalidManifestError);
+ return;
+ }
+
+ // Control flow finishes up in InstallUIProceed or InstallUIAbort.
+}
+
+void WebstoreInlineInstaller::OnWebstoreParseFailure(
+ InstallHelperResultCode result_code,
+ const std::string& error_message) {
+ CompleteInstall(error_message);
+}
+
+void WebstoreInlineInstaller::InstallUIProceed() {
+ CrxInstaller::WhitelistEntry* entry = new CrxInstaller::WhitelistEntry;
+
+ entry->parsed_manifest.reset(manifest_.get()->DeepCopy());
+ entry->localized_name = localized_name_;
+ entry->use_app_installed_bubble = true;
+ CrxInstaller::SetWhitelistEntry(id_, entry);
+
+ GURL install_url(extension_urls::GetWebstoreInstallUrl(
+ id_, g_browser_process->GetApplicationLocale()));
+
+ 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, PageTransition::LINK);
+
+ // 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).
+ CompleteInstall("");
+}
+
+void WebstoreInlineInstaller::InstallUIAbort(bool user_initiated) {
+ CompleteInstall(kUserCancelledError);
+}
+
+void WebstoreInlineInstaller::CompleteInstall(const std::string& error) {
+ if (error.empty()) {
+ delegate_->OnInlineInstallSuccess();
+ } else {
+ delegate_->OnInlineInstallFailure(error);
+ }
+ Release(); // Matches the AddRef in BeginInstall.
+}
« no previous file with comments | « chrome/browser/extensions/webstore_inline_installer.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698