1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/webstore_standalone_installer.h"
7 #include "base/values.h"
8 #include "chrome/browser/extensions/crx_installer.h"
9 #include "chrome/browser/extensions/extension_install_prompt.h"
10 #include "chrome/browser/extensions/extension_install_ui.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/webstore_data_fetcher.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/common/extensions/extension.h"
15 #include "content/public/browser/web_contents.h"
16 #include "googleurl/src/gurl.h"
18 using content::WebContents
;
20 namespace extensions
{
22 const char kManifestKey
[] = "manifest";
23 const char kIconUrlKey
[] = "icon_url";
24 const char kLocalizedNameKey
[] = "localized_name";
25 const char kLocalizedDescriptionKey
[] = "localized_description";
26 const char kUsersKey
[] = "users";
27 const char kAverageRatingKey
[] = "average_rating";
28 const char kRatingCountKey
[] = "rating_count";
29 const char kRedirectUrlKey
[] = "redirect_url";
31 const char kInvalidWebstoreItemId
[] = "Invalid Chrome Web Store item ID";
32 const char kWebstoreRequestError
[] =
33 "Could not fetch data from the Chrome Web Store";
34 const char kInvalidWebstoreResponseError
[] = "Invalid Chrome Web Store reponse";
35 const char kInvalidManifestError
[] = "Invalid manifest";
36 const char kUserCancelledError
[] = "User cancelled install";
39 WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
40 const std::string
& webstore_item_id
,
42 const Callback
& callback
)
43 : id_(webstore_item_id
),
48 CHECK(!callback_
.is_null());
51 WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}
54 // Private interface implementation.
57 void WebstoreStandaloneInstaller::BeginInstall() {
58 AddRef(); // Balanced in CompleteInstall or WebContentsDestroyed.
60 if (!Extension::IdIsValid(id_
)) {
61 CompleteInstall(kInvalidWebstoreItemId
);
65 // 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.
68 webstore_data_fetcher_
.reset(new WebstoreDataFetcher(
70 profile_
->GetRequestContext(),
73 webstore_data_fetcher_
->Start();
76 void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
77 CompleteInstall(kWebstoreRequestError
);
80 void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
81 DictionaryValue
* webstore_data
) {
82 if (!CheckRequestorAlive()) {
83 CompleteInstall(std::string());
89 if (!CheckInlineInstallPermitted(*webstore_data
, &error
)) {
90 CompleteInstall(error
);
94 if (!CheckRequestorPermitted(*webstore_data
, &error
)) {
95 CompleteInstall(error
);
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_
) ||
103 !webstore_data
->GetDouble(kAverageRatingKey
, &average_rating_
) ||
104 !webstore_data
->GetInteger(kRatingCountKey
, &rating_count_
)) {
105 CompleteInstall(kInvalidWebstoreResponseError
);
109 if (average_rating_
< ExtensionInstallPrompt::kMinExtensionRating
||
110 average_rating_
> ExtensionInstallPrompt::kMaxExtensionRating
) {
111 CompleteInstall(kInvalidWebstoreResponseError
);
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_
))) {
121 CompleteInstall(kInvalidWebstoreResponseError
);
125 // Icon URL is optional.
127 if (webstore_data
->HasKey(kIconUrlKey
)) {
128 std::string icon_url_string
;
129 if (!webstore_data
->GetString(kIconUrlKey
, &icon_url_string
)) {
130 CompleteInstall(kInvalidWebstoreResponseError
);
133 icon_url
= GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
135 if (!icon_url
.is_valid()) {
136 CompleteInstall(kInvalidWebstoreResponseError
);
141 // Assume ownership of webstore_data.
142 webstore_data_
.reset(webstore_data
);
144 scoped_refptr
<WebstoreInstallHelper
> helper
=
145 new WebstoreInstallHelper(this,
148 std::string(), // We don't have any icon data.
150 profile_
->GetRequestContext());
151 // The helper will call us back via OnWebstoreParseSucces or
152 // OnWebstoreParseFailure.
156 void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
157 const std::string
& error
) {
158 CompleteInstall(error
);
161 void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
162 const std::string
& id
,
163 const SkBitmap
& icon
,
164 base::DictionaryValue
* manifest
) {
167 if (!CheckRequestorAlive()) {
168 CompleteInstall(std::string());
172 manifest_
.reset(manifest
);
175 install_prompt_
= CreateInstallPrompt();
176 if (install_prompt_
) {
178 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
184 void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
185 const std::string
& id
,
186 InstallHelperResultCode result_code
,
187 const std::string
& error_message
) {
188 CompleteInstall(error_message
);
191 void WebstoreStandaloneInstaller::InstallUIProceed() {
192 if (!CheckRequestorAlive()) {
193 CompleteInstall(std::string());
197 scoped_ptr
<WebstoreInstaller::Approval
> approval(
198 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
201 scoped_ptr
<base::DictionaryValue
>(manifest_
.get()->DeepCopy())));
202 approval
->skip_post_install_ui
= !ShouldShowPostInstallUI();
203 approval
->use_app_installed_bubble
= ShouldShowAppInstalledBubble();
205 scoped_refptr
<WebstoreInstaller
> installer
= new WebstoreInstaller(
208 &(GetWebContents()->GetController()),
211 WebstoreInstaller::FLAG_INLINE_INSTALL
);
215 void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated
) {
216 CompleteInstall(kUserCancelledError
);
219 void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
220 const std::string
& id
) {
222 CompleteInstall(std::string());
225 void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
226 const std::string
& id
,
227 const std::string
& error
,
228 WebstoreInstaller::FailureReason cancelled
) {
230 CompleteInstall(error
);
233 void WebstoreStandaloneInstaller::AbortInstall() {
235 // Abort any in-progress fetches.
236 if (webstore_data_fetcher_
) {
237 webstore_data_fetcher_
.reset();
238 Release(); // Matches the AddRef in BeginInstall.
242 void WebstoreStandaloneInstaller::CompleteInstall(const std::string
& error
) {
243 // 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());
247 if (!callback_
.is_null())
248 callback_
.Run(error
.empty(), error
);
250 Release(); // Matches the AddRef in BeginInstall.
254 WebstoreStandaloneInstaller::CreateInstallUI() {
256 localized_extension_for_display_
=
257 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
259 Extension::REQUIRE_KEY
| Extension::FROM_WEBSTORE
,
262 localized_description_
,
264 if (!localized_extension_for_display_
.get()) {
265 CompleteInstall(kInvalidManifestError
);
269 install_ui_
.reset(new ExtensionInstallPrompt(GetWebContents()));
270 install_ui_
->ConfirmStandaloneInstall(
271 this, localized_extension_for_display_
.get(), &icon_
, *install_prompt_
);
274 } // namespace extensions