blob: 7df550f80bab3e75bd2722d889f9e61debba871e [file] [log] [blame]
[email protected]bdb74a22012-01-25 20:33:331// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]8915f342011-08-29 22:14:372// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]734bcec2012-10-08 20:29:055#include "chrome/browser/extensions/webstore_standalone_installer.h"
[email protected]8915f342011-08-29 22:14:376
[email protected]8915f342011-08-29 22:14:377#include "base/values.h"
[email protected]8915f342011-08-29 22:14:378#include "chrome/browser/extensions/crx_installer.h"
[email protected]d44ec7b2013-03-15 04:34:349#include "chrome/browser/extensions/extension_install_prompt.h"
[email protected]00b38242012-07-18 18:43:2210#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]655b2b1a2011-10-13 17:13:0611#include "chrome/browser/extensions/extension_service.h"
[email protected]7b3941052013-02-13 01:21:5912#include "chrome/browser/extensions/webstore_data_fetcher.h"
[email protected]8915f342011-08-29 22:14:3713#include "chrome/browser/profiles/profile.h"
[email protected]8915f342011-08-29 22:14:3714#include "chrome/common/extensions/extension.h"
[email protected]10c2d692012-05-11 05:32:2315#include "content/public/browser/web_contents.h"
[email protected]d44ec7b2013-03-15 04:34:3416#include "googleurl/src/gurl.h"
[email protected]8915f342011-08-29 22:14:3717
[email protected]26b5e322011-12-23 01:36:4718using content::WebContents;
[email protected]631bb742011-11-02 11:29:3919
[email protected]3d61a7f2012-07-12 19:11:2520namespace extensions {
21
[email protected]8915f342011-08-29 22:14:3722const char kManifestKey[] = "manifest";
23const char kIconUrlKey[] = "icon_url";
24const char kLocalizedNameKey[] = "localized_name";
[email protected]5fdbd6f2011-09-01 17:33:0425const char kLocalizedDescriptionKey[] = "localized_description";
26const char kUsersKey[] = "users";
27const char kAverageRatingKey[] = "average_rating";
28const char kRatingCountKey[] = "rating_count";
[email protected]dd5161a2011-09-14 17:40:1729const char kRedirectUrlKey[] = "redirect_url";
[email protected]8915f342011-08-29 22:14:3730
[email protected]a221ef092011-09-07 01:34:1031const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
32const char kWebstoreRequestError[] =
33 "Could not fetch data from the Chrome Web Store";
34const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
[email protected]8915f342011-08-29 22:14:3735const char kInvalidManifestError[] = "Invalid manifest";
36const char kUserCancelledError[] = "User cancelled install";
[email protected]d44ec7b2013-03-15 04:34:3437
[email protected]8915f342011-08-29 22:14:3738
[email protected]734bcec2012-10-08 20:29:0539WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
[email protected]d44ec7b2013-03-15 04:34:3440 const std::string& webstore_item_id,
[email protected]c1b2d042013-02-23 00:31:0441 Profile* profile,
[email protected]c1b2d042013-02-23 00:31:0442 const Callback& callback)
[email protected]d44ec7b2013-03-15 04:34:3443 : id_(webstore_item_id),
[email protected]d2a639e2012-09-17 07:41:2144 callback_(callback),
[email protected]d44ec7b2013-03-15 04:34:3445 profile_(profile),
[email protected]c7bf7452011-09-12 21:31:5046 average_rating_(0.0),
[email protected]5f2a4752012-04-27 22:18:5847 rating_count_(0) {
[email protected]c1b2d042013-02-23 00:31:0448 CHECK(!callback_.is_null());
49}
50
[email protected]d44ec7b2013-03-15 04:34:3451WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}
52
53//
54// Private interface implementation.
55//
[email protected]8915f342011-08-29 22:14:3756
[email protected]734bcec2012-10-08 20:29:0557void WebstoreStandaloneInstaller::BeginInstall() {
[email protected]5db2e882012-12-20 10:17:2658 AddRef(); // Balanced in CompleteInstall or WebContentsDestroyed.
[email protected]8915f342011-08-29 22:14:3759
[email protected]3d61a7f2012-07-12 19:11:2560 if (!Extension::IdIsValid(id_)) {
[email protected]8915f342011-08-29 22:14:3761 CompleteInstall(kInvalidWebstoreItemId);
62 return;
63 }
64
[email protected]b4574c02011-11-17 06:19:1365 // Use the requesting page as the referrer both since that is more correct
66 // (it is the page that caused this request to happen) and so that we can
67 // track top sites that trigger inline install requests.
[email protected]7b3941052013-02-13 01:21:5968 webstore_data_fetcher_.reset(new WebstoreDataFetcher(
69 this,
[email protected]c1b2d042013-02-23 00:31:0470 profile_->GetRequestContext(),
[email protected]d44ec7b2013-03-15 04:34:3471 GetRequestorURL(),
[email protected]7b3941052013-02-13 01:21:5972 id_));
73 webstore_data_fetcher_->Start();
[email protected]8915f342011-08-29 22:14:3774}
75
[email protected]7b3941052013-02-13 01:21:5976void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
77 CompleteInstall(kWebstoreRequestError);
[email protected]8915f342011-08-29 22:14:3778}
79
[email protected]734bcec2012-10-08 20:29:0580void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
[email protected]8915f342011-08-29 22:14:3781 DictionaryValue* webstore_data) {
[email protected]d44ec7b2013-03-15 04:34:3482 if (!CheckRequestorAlive()) {
[email protected]007b3f82013-04-09 08:46:4583 CompleteInstall(std::string());
[email protected]4693243e2011-09-09 23:52:3784 return;
85 }
86
[email protected]d44ec7b2013-03-15 04:34:3487 std::string error;
[email protected]8915f342011-08-29 22:14:3788
[email protected]d44ec7b2013-03-15 04:34:3489 if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
90 CompleteInstall(error);
[email protected]8915f342011-08-29 22:14:3791 return;
92 }
[email protected]8915f342011-08-29 22:14:3793
[email protected]d44ec7b2013-03-15 04:34:3494 if (!CheckRequestorPermitted(*webstore_data, &error)) {
95 CompleteInstall(error);
[email protected]dd5161a2011-09-14 17:40:1796 return;
97 }
98
99 // Manifest, number of users, average rating and rating count are required.
100 std::string manifest;
101 if (!webstore_data->GetString(kManifestKey, &manifest) ||
102 !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
[email protected]5fdbd6f2011-09-01 17:33:04103 !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
104 !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
105 CompleteInstall(kInvalidWebstoreResponseError);
106 return;
107 }
108
[email protected]c82da8c42012-06-08 19:49:11109 if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
110 average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
[email protected]5fdbd6f2011-09-01 17:33:04111 CompleteInstall(kInvalidWebstoreResponseError);
112 return;
113 }
114
115 // Localized name and description are optional.
116 if ((webstore_data->HasKey(kLocalizedNameKey) &&
117 !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
118 (webstore_data->HasKey(kLocalizedDescriptionKey) &&
119 !webstore_data->GetString(
120 kLocalizedDescriptionKey, &localized_description_))) {
[email protected]8915f342011-08-29 22:14:37121 CompleteInstall(kInvalidWebstoreResponseError);
122 return;
123 }
124
125 // Icon URL is optional.
126 GURL icon_url;
127 if (webstore_data->HasKey(kIconUrlKey)) {
128 std::string icon_url_string;
129 if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
130 CompleteInstall(kInvalidWebstoreResponseError);
131 return;
132 }
133 icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
134 icon_url_string);
135 if (!icon_url.is_valid()) {
136 CompleteInstall(kInvalidWebstoreResponseError);
137 return;
138 }
139 }
140
[email protected]d44ec7b2013-03-15 04:34:34141 // Assume ownership of webstore_data.
142 webstore_data_.reset(webstore_data);
[email protected]a221ef092011-09-07 01:34:10143
[email protected]007b3f82013-04-09 08:46:45144 scoped_refptr<WebstoreInstallHelper> helper =
145 new WebstoreInstallHelper(this,
146 id_,
147 manifest,
148 std::string(), // We don't have any icon data.
149 icon_url,
150 profile_->GetRequestContext());
[email protected]8915f342011-08-29 22:14:37151 // The helper will call us back via OnWebstoreParseSucces or
152 // OnWebstoreParseFailure.
153 helper->Start();
154}
155
[email protected]734bcec2012-10-08 20:29:05156void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
[email protected]8915f342011-08-29 22:14:37157 const std::string& error) {
158 CompleteInstall(error);
159}
160
[email protected]734bcec2012-10-08 20:29:05161void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
[email protected]98e4e522011-10-25 13:00:16162 const std::string& id,
[email protected]8915f342011-08-29 22:14:37163 const SkBitmap& icon,
164 base::DictionaryValue* manifest) {
[email protected]d44ec7b2013-03-15 04:34:34165 CHECK_EQ(id_, id);
166
167 if (!CheckRequestorAlive()) {
[email protected]007b3f82013-04-09 08:46:45168 CompleteInstall(std::string());
[email protected]2fd920fb2011-09-08 23:33:00169 return;
170 }
171
[email protected]8915f342011-08-29 22:14:37172 manifest_.reset(manifest);
173 icon_ = icon;
174
[email protected]d44ec7b2013-03-15 04:34:34175 install_prompt_ = CreateInstallPrompt();
176 if (install_prompt_) {
177 CreateInstallUI();
178 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
179 } else {
[email protected]77e9261d2013-02-04 22:01:47180 InstallUIProceed();
[email protected]77e9261d2013-02-04 22:01:47181 }
[email protected]8915f342011-08-29 22:14:37182}
183
[email protected]734bcec2012-10-08 20:29:05184void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
[email protected]98e4e522011-10-25 13:00:16185 const std::string& id,
[email protected]8915f342011-08-29 22:14:37186 InstallHelperResultCode result_code,
187 const std::string& error_message) {
188 CompleteInstall(error_message);
189}
190
[email protected]734bcec2012-10-08 20:29:05191void WebstoreStandaloneInstaller::InstallUIProceed() {
[email protected]d44ec7b2013-03-15 04:34:34192 if (!CheckRequestorAlive()) {
[email protected]007b3f82013-04-09 08:46:45193 CompleteInstall(std::string());
[email protected]2fd920fb2011-09-08 23:33:00194 return;
195 }
196
[email protected]21a5ad62012-04-03 04:48:45197 scoped_ptr<WebstoreInstaller::Approval> approval(
[email protected]89019d62012-05-17 18:47:09198 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
[email protected]c1b2d042013-02-23 00:31:04199 profile_,
[email protected]89019d62012-05-17 18:47:09200 id_,
201 scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy())));
[email protected]d44ec7b2013-03-15 04:34:34202 approval->skip_post_install_ui = !ShouldShowPostInstallUI();
203 approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
[email protected]21a5ad62012-04-03 04:48:45204
[email protected]98e4e522011-10-25 13:00:16205 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
[email protected]d44ec7b2013-03-15 04:34:34206 profile_,
207 this,
208 &(GetWebContents()->GetController()),
209 id_,
210 approval.Pass(),
[email protected]98e4e522011-10-25 13:00:16211 WebstoreInstaller::FLAG_INLINE_INSTALL);
212 installer->Start();
[email protected]8915f342011-08-29 22:14:37213}
214
[email protected]734bcec2012-10-08 20:29:05215void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
[email protected]8915f342011-08-29 22:14:37216 CompleteInstall(kUserCancelledError);
217}
218
[email protected]734bcec2012-10-08 20:29:05219void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
220 const std::string& id) {
[email protected]cb08ba22011-10-19 21:41:40221 CHECK_EQ(id_, id);
[email protected]007b3f82013-04-09 08:46:45222 CompleteInstall(std::string());
[email protected]cb08ba22011-10-19 21:41:40223}
224
[email protected]734bcec2012-10-08 20:29:05225void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
[email protected]bcd1eaf72012-10-03 05:42:29226 const std::string& id,
227 const std::string& error,
228 WebstoreInstaller::FailureReason cancelled) {
[email protected]cb08ba22011-10-19 21:41:40229 CHECK_EQ(id_, id);
230 CompleteInstall(error);
231}
232
[email protected]d44ec7b2013-03-15 04:34:34233void WebstoreStandaloneInstaller::AbortInstall() {
234 callback_.Reset();
235 // Abort any in-progress fetches.
236 if (webstore_data_fetcher_.get()) {
237 webstore_data_fetcher_.reset();
238 Release(); // Matches the AddRef in BeginInstall.
239 }
240}
241
[email protected]734bcec2012-10-08 20:29:05242void WebstoreStandaloneInstaller::CompleteInstall(const std::string& error) {
[email protected]0688d8dc2013-02-16 04:10:38243 // Clear webstore_data_fetcher_ so that WebContentsDestroyed will no longer
244 // call Release in case the WebContents is destroyed before this object.
245 scoped_ptr<WebstoreDataFetcher> webstore_data_fetcher(
246 webstore_data_fetcher_.Pass());
[email protected]d2a639e2012-09-17 07:41:21247 if (!callback_.is_null())
248 callback_.Run(error.empty(), error);
[email protected]2fd920fb2011-09-08 23:33:00249
[email protected]5db2e882012-12-20 10:17:26250 Release(); // Matches the AddRef in BeginInstall.
[email protected]8915f342011-08-29 22:14:37251}
[email protected]5f2a4752012-04-27 22:18:58252
[email protected]d44ec7b2013-03-15 04:34:34253void
254WebstoreStandaloneInstaller::CreateInstallUI() {
255 std::string error;
256 localized_extension_for_display_ =
257 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
258 manifest_.get(),
259 Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
260 id_,
261 localized_name_,
262 localized_description_,
263 &error);
264 if (!localized_extension_for_display_) {
265 CompleteInstall(kInvalidManifestError);
266 return;
[email protected]5f2a4752012-04-27 22:18:58267 }
[email protected]5f2a4752012-04-27 22:18:58268
[email protected]d44ec7b2013-03-15 04:34:34269 install_ui_.reset(new ExtensionInstallPrompt(GetWebContents()));
270 install_ui_->ConfirmStandaloneInstall(this,
271 localized_extension_for_display_,
272 &icon_,
273 *install_prompt_);
[email protected]5f2a4752012-04-27 22:18:58274}
[email protected]3d61a7f2012-07-12 19:11:25275
276} // namespace extensions