[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 1 | // Copyright (c) 2011 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. |
| 4 | |
| 5 | #include "chrome/browser/extensions/webstore_inline_installer.h" |
| 6 | |
| 7 | #include <vector> |
| 8 | |
[email protected] | 8e6ac4b | 2011-10-17 19:04:31 | [diff] [blame] | 9 | #include "base/bind.h" |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 10 | #include "base/string_util.h" |
| 11 | #include "base/values.h" |
| 12 | #include "chrome/browser/browser_process.h" |
| 13 | #include "chrome/browser/extensions/crx_installer.h" |
| 14 | #include "chrome/browser/extensions/extension_install_dialog.h" |
[email protected] | 655b2b1a | 2011-10-13 17:13:06 | [diff] [blame] | 15 | #include "chrome/browser/extensions/extension_service.h" |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 16 | #include "chrome/browser/profiles/profile.h" |
| 17 | #include "chrome/common/chrome_utility_messages.h" |
| 18 | #include "chrome/common/extensions/extension.h" |
| 19 | #include "chrome/common/extensions/extension_constants.h" |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 20 | #include "chrome/common/extensions/url_pattern.h" |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 21 | #include "content/browser/tab_contents/tab_contents.h" |
| 22 | #include "content/browser/utility_process_host.h" |
[email protected] | 7b419b8 | 2011-10-27 04:23:46 | [diff] [blame] | 23 | #include "content/public/common/url_fetcher.h" |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 24 | #include "net/base/escape.h" |
[email protected] | 41e9a0de | 2011-09-14 17:24:51 | [diff] [blame] | 25 | #include "net/base/load_flags.h" |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 26 | #include "net/url_request/url_request_status.h" |
| 27 | |
[email protected] | 631bb74 | 2011-11-02 11:29:39 | [diff] [blame] | 28 | using content::BrowserThread; |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame^] | 29 | using content::WebContents; |
[email protected] | 631bb74 | 2011-11-02 11:29:39 | [diff] [blame] | 30 | |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 31 | const char kManifestKey[] = "manifest"; |
| 32 | const char kIconUrlKey[] = "icon_url"; |
| 33 | const char kLocalizedNameKey[] = "localized_name"; |
[email protected] | 5fdbd6f | 2011-09-01 17:33:04 | [diff] [blame] | 34 | const char kLocalizedDescriptionKey[] = "localized_description"; |
| 35 | const char kUsersKey[] = "users"; |
| 36 | const char kAverageRatingKey[] = "average_rating"; |
| 37 | const char kRatingCountKey[] = "rating_count"; |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 38 | const char kVerifiedSiteKey[] = "verified_site"; |
[email protected] | dd5161a | 2011-09-14 17:40:17 | [diff] [blame] | 39 | const char kInlineInstallNotSupportedKey[] = "inline_install_not_supported"; |
| 40 | const char kRedirectUrlKey[] = "redirect_url"; |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 41 | |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 42 | const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID"; |
| 43 | const char kWebstoreRequestError[] = |
| 44 | "Could not fetch data from the Chrome Web Store"; |
| 45 | const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse"; |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 46 | const char kInvalidManifestError[] = "Invalid manifest"; |
| 47 | const char kUserCancelledError[] = "User cancelled install"; |
[email protected] | 5da311ea | 2011-09-14 20:57:32 | [diff] [blame] | 48 | const char kNoVerifiedSiteError[] = |
| 49 | "Inline installs can only be initiated for Chrome Web Store items that " |
| 50 | "have a verified site"; |
| 51 | const char kNotFromVerifiedSiteError[] = |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 52 | "Installs can only be initiated by the Chrome Web Store item's verified " |
| 53 | "site"; |
[email protected] | dd5161a | 2011-09-14 17:40:17 | [diff] [blame] | 54 | const char kInlineInstallSupportedError[] = |
| 55 | "Inline installation is not supported for this item. The user will be " |
| 56 | "redirected to the Chrome Web Store."; |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 57 | |
| 58 | class SafeWebstoreResponseParser : public UtilityProcessHost::Client { |
| 59 | public: |
| 60 | SafeWebstoreResponseParser(WebstoreInlineInstaller *client, |
| 61 | const std::string& webstore_data) |
| 62 | : client_(client), |
| 63 | webstore_data_(webstore_data), |
| 64 | utility_host_(NULL) {} |
| 65 | |
| 66 | void Start() { |
| 67 | CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 68 | BrowserThread::PostTask( |
| 69 | BrowserThread::IO, |
| 70 | FROM_HERE, |
[email protected] | 8e6ac4b | 2011-10-17 19:04:31 | [diff] [blame] | 71 | base::Bind(&SafeWebstoreResponseParser::StartWorkOnIOThread, this)); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | void StartWorkOnIOThread() { |
| 75 | CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 76 | utility_host_ = new UtilityProcessHost(this, BrowserThread::IO); |
[email protected] | 3dd18d0 | 2011-12-13 19:32:38 | [diff] [blame] | 77 | utility_host_->set_use_linux_zygote(true); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 78 | utility_host_->Send(new ChromeUtilityMsg_ParseJSON(webstore_data_)); |
| 79 | } |
| 80 | |
| 81 | // Implementing pieces of the UtilityProcessHost::Client interface. |
| 82 | virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
| 83 | bool handled = true; |
| 84 | IPC_BEGIN_MESSAGE_MAP(SafeWebstoreResponseParser, message) |
| 85 | IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded, |
| 86 | OnJSONParseSucceeded) |
| 87 | IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed, |
| 88 | OnJSONParseFailed) |
| 89 | IPC_MESSAGE_UNHANDLED(handled = false) |
| 90 | IPC_END_MESSAGE_MAP() |
| 91 | return handled; |
| 92 | } |
| 93 | |
| 94 | void OnJSONParseSucceeded(const ListValue& wrapper) { |
| 95 | CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 96 | Value* value = NULL; |
| 97 | CHECK(wrapper.Get(0, &value)); |
| 98 | if (value->IsType(Value::TYPE_DICTIONARY)) { |
| 99 | parsed_webstore_data_.reset( |
| 100 | static_cast<DictionaryValue*>(value)->DeepCopy()); |
| 101 | } else { |
| 102 | error_ = kInvalidWebstoreResponseError; |
| 103 | } |
| 104 | |
| 105 | ReportResults(); |
| 106 | } |
| 107 | |
| 108 | virtual void OnJSONParseFailed(const std::string& error_message) { |
| 109 | CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 110 | error_ = error_message; |
| 111 | ReportResults(); |
| 112 | } |
| 113 | |
| 114 | void ReportResults() { |
| 115 | CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 116 | |
| 117 | // The utility_host_ will take care of deleting itself after this call. |
| 118 | utility_host_ = NULL; |
| 119 | |
| 120 | BrowserThread::PostTask( |
| 121 | BrowserThread::UI, |
| 122 | FROM_HERE, |
[email protected] | 8e6ac4b | 2011-10-17 19:04:31 | [diff] [blame] | 123 | base::Bind(&SafeWebstoreResponseParser::ReportResultOnUIThread, this)); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 124 | } |
| 125 | |
| 126 | void ReportResultOnUIThread() { |
| 127 | CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 128 | if (error_.empty() && parsed_webstore_data_.get()) { |
| 129 | client_->OnWebstoreResponseParseSuccess(parsed_webstore_data_.release()); |
| 130 | } else { |
| 131 | client_->OnWebstoreResponseParseFailure(error_); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | private: |
| 136 | virtual ~SafeWebstoreResponseParser() {} |
| 137 | |
| 138 | WebstoreInlineInstaller* client_; |
| 139 | |
| 140 | std::string webstore_data_; |
| 141 | |
| 142 | UtilityProcessHost* utility_host_; |
| 143 | |
| 144 | std::string error_; |
| 145 | scoped_ptr<DictionaryValue> parsed_webstore_data_; |
| 146 | }; |
| 147 | |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame^] | 148 | WebstoreInlineInstaller::WebstoreInlineInstaller(WebContents* web_contents, |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 149 | int install_id, |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 150 | std::string webstore_item_id, |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 151 | GURL requestor_url, |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 152 | Delegate* delegate) |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame^] | 153 | : content::WebContentsObserver(web_contents), |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 154 | install_id_(install_id), |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 155 | id_(webstore_item_id), |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 156 | requestor_url_(requestor_url), |
[email protected] | c7bf745 | 2011-09-12 21:31:50 | [diff] [blame] | 157 | delegate_(delegate), |
| 158 | average_rating_(0.0), |
| 159 | rating_count_(0) {} |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 160 | |
| 161 | WebstoreInlineInstaller::~WebstoreInlineInstaller() { |
| 162 | } |
| 163 | |
| 164 | void WebstoreInlineInstaller::BeginInstall() { |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame^] | 165 | AddRef(); // Balanced in CompleteInstall or WebContentsDestroyed. |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 166 | |
| 167 | if (!Extension::IdIsValid(id_)) { |
| 168 | CompleteInstall(kInvalidWebstoreItemId); |
| 169 | return; |
| 170 | } |
| 171 | |
| 172 | GURL webstore_data_url(extension_urls::GetWebstoreItemJsonDataURL(id_)); |
| 173 | |
[email protected] | 36aea270 | 2011-10-26 01:12:22 | [diff] [blame] | 174 | webstore_data_url_fetcher_.reset(content::URLFetcher::Create( |
| 175 | webstore_data_url, content::URLFetcher::GET, this)); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 176 | Profile* profile = Profile::FromBrowserContext( |
[email protected] | 627e051 | 2011-12-21 22:55:30 | [diff] [blame] | 177 | tab_contents()->GetBrowserContext()); |
[email protected] | 7cc6e563 | 2011-10-25 17:56:12 | [diff] [blame] | 178 | webstore_data_url_fetcher_->SetRequestContext( |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 179 | profile->GetRequestContext()); |
[email protected] | b4574c0 | 2011-11-17 06:19:13 | [diff] [blame] | 180 | // Use the requesting page as the referrer both since that is more correct |
| 181 | // (it is the page that caused this request to happen) and so that we can |
| 182 | // track top sites that trigger inline install requests. |
| 183 | webstore_data_url_fetcher_->SetReferrer(requestor_url_.spec()); |
[email protected] | 7cc6e563 | 2011-10-25 17:56:12 | [diff] [blame] | 184 | webstore_data_url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 185 | net::LOAD_DO_NOT_SAVE_COOKIES | |
| 186 | net::LOAD_DISABLE_CACHE); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 187 | webstore_data_url_fetcher_->Start(); |
| 188 | } |
| 189 | |
[email protected] | 7cc6e563 | 2011-10-25 17:56:12 | [diff] [blame] | 190 | void WebstoreInlineInstaller::OnURLFetchComplete( |
| 191 | const content::URLFetcher* source) { |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 192 | CHECK_EQ(webstore_data_url_fetcher_.get(), source); |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame^] | 193 | // We shouldn't be getting UrlFetcher callbacks if the WebContents has gone |
| 194 | // away; we stop any in in-progress fetches in WebContentsDestroyed. |
[email protected] | 2fd920fb | 2011-09-08 23:33:00 | [diff] [blame] | 195 | CHECK(tab_contents()); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 196 | |
[email protected] | 7cc6e563 | 2011-10-25 17:56:12 | [diff] [blame] | 197 | if (!webstore_data_url_fetcher_->GetStatus().is_success() || |
| 198 | webstore_data_url_fetcher_->GetResponseCode() != 200) { |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 199 | CompleteInstall(kWebstoreRequestError); |
| 200 | return; |
| 201 | } |
| 202 | |
| 203 | std::string webstore_json_data; |
| 204 | webstore_data_url_fetcher_->GetResponseAsString(&webstore_json_data); |
| 205 | webstore_data_url_fetcher_.reset(); |
| 206 | |
| 207 | scoped_refptr<SafeWebstoreResponseParser> parser = |
| 208 | new SafeWebstoreResponseParser(this, webstore_json_data); |
| 209 | // The parser will call us back via OnWebstoreResponseParseSucces or |
| 210 | // OnWebstoreResponseParseFailure. |
| 211 | parser->Start(); |
| 212 | } |
| 213 | |
| 214 | void WebstoreInlineInstaller::OnWebstoreResponseParseSuccess( |
| 215 | DictionaryValue* webstore_data) { |
[email protected] | 4693243e | 2011-09-09 23:52:37 | [diff] [blame] | 216 | // Check if the tab has gone away in the meantime. |
| 217 | if (!tab_contents()) { |
| 218 | CompleteInstall(""); |
| 219 | return; |
| 220 | } |
| 221 | |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 222 | webstore_data_.reset(webstore_data); |
| 223 | |
[email protected] | dd5161a | 2011-09-14 17:40:17 | [diff] [blame] | 224 | // The store may not support inline installs for this item, in which case |
| 225 | // we open the store-provided redirect URL in a new tab and abort the |
| 226 | // installation process. |
| 227 | bool inline_install_not_supported = false; |
| 228 | if (webstore_data->HasKey(kInlineInstallNotSupportedKey) && |
| 229 | !webstore_data->GetBoolean( |
| 230 | kInlineInstallNotSupportedKey, &inline_install_not_supported)) { |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 231 | CompleteInstall(kInvalidWebstoreResponseError); |
| 232 | return; |
| 233 | } |
[email protected] | dd5161a | 2011-09-14 17:40:17 | [diff] [blame] | 234 | if (inline_install_not_supported) { |
| 235 | std::string redirect_url; |
| 236 | if (!webstore_data->GetString(kRedirectUrlKey, &redirect_url)) { |
| 237 | CompleteInstall(kInvalidWebstoreResponseError); |
| 238 | return; |
| 239 | } |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 240 | |
[email protected] | dd5161a | 2011-09-14 17:40:17 | [diff] [blame] | 241 | tab_contents()->OpenURL(OpenURLParams( |
| 242 | GURL(redirect_url), |
[email protected] | bce1f1c | 2011-12-05 15:11:58 | [diff] [blame] | 243 | content::Referrer(tab_contents()->GetURL(), |
| 244 | WebKit::WebReferrerPolicyDefault), |
[email protected] | dd5161a | 2011-09-14 17:40:17 | [diff] [blame] | 245 | NEW_FOREGROUND_TAB, |
[email protected] | e47ae947 | 2011-10-13 19:48:34 | [diff] [blame] | 246 | content::PAGE_TRANSITION_AUTO_BOOKMARK, |
| 247 | false)); |
[email protected] | dd5161a | 2011-09-14 17:40:17 | [diff] [blame] | 248 | CompleteInstall(kInlineInstallSupportedError); |
| 249 | return; |
| 250 | } |
| 251 | |
| 252 | // Manifest, number of users, average rating and rating count are required. |
| 253 | std::string manifest; |
| 254 | if (!webstore_data->GetString(kManifestKey, &manifest) || |
| 255 | !webstore_data->GetString(kUsersKey, &localized_user_count_) || |
[email protected] | 5fdbd6f | 2011-09-01 17:33:04 | [diff] [blame] | 256 | !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) || |
| 257 | !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) { |
| 258 | CompleteInstall(kInvalidWebstoreResponseError); |
| 259 | return; |
| 260 | } |
| 261 | |
| 262 | if (average_rating_ < ExtensionInstallUI::kMinExtensionRating || |
| 263 | average_rating_ >ExtensionInstallUI::kMaxExtensionRating) { |
| 264 | CompleteInstall(kInvalidWebstoreResponseError); |
| 265 | return; |
| 266 | } |
| 267 | |
| 268 | // Localized name and description are optional. |
| 269 | if ((webstore_data->HasKey(kLocalizedNameKey) && |
| 270 | !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) || |
| 271 | (webstore_data->HasKey(kLocalizedDescriptionKey) && |
| 272 | !webstore_data->GetString( |
| 273 | kLocalizedDescriptionKey, &localized_description_))) { |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 274 | CompleteInstall(kInvalidWebstoreResponseError); |
| 275 | return; |
| 276 | } |
| 277 | |
| 278 | // Icon URL is optional. |
| 279 | GURL icon_url; |
| 280 | if (webstore_data->HasKey(kIconUrlKey)) { |
| 281 | std::string icon_url_string; |
| 282 | if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) { |
| 283 | CompleteInstall(kInvalidWebstoreResponseError); |
| 284 | return; |
| 285 | } |
| 286 | icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve( |
| 287 | icon_url_string); |
| 288 | if (!icon_url.is_valid()) { |
| 289 | CompleteInstall(kInvalidWebstoreResponseError); |
| 290 | return; |
| 291 | } |
| 292 | } |
| 293 | |
[email protected] | 5da311ea | 2011-09-14 20:57:32 | [diff] [blame] | 294 | // Verified site is required |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 295 | if (webstore_data->HasKey(kVerifiedSiteKey)) { |
| 296 | std::string verified_site_domain; |
| 297 | if (!webstore_data->GetString(kVerifiedSiteKey, &verified_site_domain)) { |
| 298 | CompleteInstall(kInvalidWebstoreResponseError); |
| 299 | return; |
| 300 | } |
| 301 | |
[email protected] | 838b943 | 2011-12-19 05:15:15 | [diff] [blame] | 302 | URLPattern verified_site_pattern(URLPattern::SCHEME_ALL); |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 303 | verified_site_pattern.SetScheme("*"); |
| 304 | verified_site_pattern.SetHost(verified_site_domain); |
| 305 | verified_site_pattern.SetMatchSubdomains(true); |
| 306 | verified_site_pattern.SetPath("/*"); |
| 307 | |
| 308 | if (!verified_site_pattern.MatchesURL(requestor_url_)) { |
[email protected] | 5da311ea | 2011-09-14 20:57:32 | [diff] [blame] | 309 | CompleteInstall(kNotFromVerifiedSiteError); |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 310 | return; |
| 311 | } |
[email protected] | 5da311ea | 2011-09-14 20:57:32 | [diff] [blame] | 312 | } else { |
| 313 | CompleteInstall(kNoVerifiedSiteError); |
| 314 | return; |
[email protected] | a221ef09 | 2011-09-07 01:34:10 | [diff] [blame] | 315 | } |
| 316 | |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 317 | scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( |
| 318 | this, |
[email protected] | 98e4e52 | 2011-10-25 13:00:16 | [diff] [blame] | 319 | id_, |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 320 | manifest, |
| 321 | "", // We don't have any icon data. |
| 322 | icon_url, |
[email protected] | 627e051 | 2011-12-21 22:55:30 | [diff] [blame] | 323 | Profile::FromBrowserContext(tab_contents()->GetBrowserContext())-> |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 324 | GetRequestContext()); |
| 325 | // The helper will call us back via OnWebstoreParseSucces or |
| 326 | // OnWebstoreParseFailure. |
| 327 | helper->Start(); |
| 328 | } |
| 329 | |
| 330 | void WebstoreInlineInstaller::OnWebstoreResponseParseFailure( |
| 331 | const std::string& error) { |
| 332 | CompleteInstall(error); |
| 333 | } |
| 334 | |
| 335 | void WebstoreInlineInstaller::OnWebstoreParseSuccess( |
[email protected] | 98e4e52 | 2011-10-25 13:00:16 | [diff] [blame] | 336 | const std::string& id, |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 337 | const SkBitmap& icon, |
| 338 | base::DictionaryValue* manifest) { |
[email protected] | 2fd920fb | 2011-09-08 23:33:00 | [diff] [blame] | 339 | // Check if the tab has gone away in the meantime. |
| 340 | if (!tab_contents()) { |
| 341 | CompleteInstall(""); |
| 342 | return; |
| 343 | } |
| 344 | |
[email protected] | 98e4e52 | 2011-10-25 13:00:16 | [diff] [blame] | 345 | CHECK_EQ(id_, id); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 346 | manifest_.reset(manifest); |
| 347 | icon_ = icon; |
| 348 | |
| 349 | Profile* profile = Profile::FromBrowserContext( |
[email protected] | 627e051 | 2011-12-21 22:55:30 | [diff] [blame] | 350 | tab_contents()->GetBrowserContext()); |
[email protected] | 5fdbd6f | 2011-09-01 17:33:04 | [diff] [blame] | 351 | |
| 352 | ExtensionInstallUI::Prompt prompt(ExtensionInstallUI::INLINE_INSTALL_PROMPT); |
[email protected] | 122e8df | 2011-09-02 18:20:24 | [diff] [blame] | 353 | prompt.SetInlineInstallWebstoreData(localized_user_count_, |
| 354 | average_rating_, |
| 355 | rating_count_); |
[email protected] | 5fdbd6f | 2011-09-01 17:33:04 | [diff] [blame] | 356 | |
[email protected] | d0243b05 | 2011-09-10 18:35:11 | [diff] [blame] | 357 | if (!ShowExtensionInstallDialogForManifest(profile, |
| 358 | this, |
| 359 | manifest, |
| 360 | id_, |
| 361 | localized_name_, |
| 362 | localized_description_, |
| 363 | &icon_, |
| 364 | prompt, |
| 365 | &dummy_extension_)) { |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 366 | CompleteInstall(kInvalidManifestError); |
| 367 | return; |
| 368 | } |
| 369 | |
| 370 | // Control flow finishes up in InstallUIProceed or InstallUIAbort. |
| 371 | } |
| 372 | |
| 373 | void WebstoreInlineInstaller::OnWebstoreParseFailure( |
[email protected] | 98e4e52 | 2011-10-25 13:00:16 | [diff] [blame] | 374 | const std::string& id, |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 375 | InstallHelperResultCode result_code, |
| 376 | const std::string& error_message) { |
| 377 | CompleteInstall(error_message); |
| 378 | } |
| 379 | |
| 380 | void WebstoreInlineInstaller::InstallUIProceed() { |
[email protected] | 2fd920fb | 2011-09-08 23:33:00 | [diff] [blame] | 381 | // Check if the tab has gone away in the meantime. |
| 382 | if (!tab_contents()) { |
| 383 | CompleteInstall(""); |
| 384 | return; |
| 385 | } |
| 386 | |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 387 | CrxInstaller::WhitelistEntry* entry = new CrxInstaller::WhitelistEntry; |
| 388 | |
| 389 | entry->parsed_manifest.reset(manifest_.get()->DeepCopy()); |
| 390 | entry->localized_name = localized_name_; |
| 391 | entry->use_app_installed_bubble = true; |
| 392 | CrxInstaller::SetWhitelistEntry(id_, entry); |
| 393 | |
[email protected] | 655b2b1a | 2011-10-13 17:13:06 | [diff] [blame] | 394 | Profile* profile = Profile::FromBrowserContext( |
[email protected] | 627e051 | 2011-12-21 22:55:30 | [diff] [blame] | 395 | tab_contents()->GetBrowserContext()); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 396 | |
[email protected] | 98e4e52 | 2011-10-25 13:00:16 | [diff] [blame] | 397 | scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller( |
[email protected] | f5fa20e | 2011-12-21 22:35:56 | [diff] [blame] | 398 | profile, this, &(tab_contents()->GetController()), id_, |
[email protected] | 98e4e52 | 2011-10-25 13:00:16 | [diff] [blame] | 399 | WebstoreInstaller::FLAG_INLINE_INSTALL); |
| 400 | installer->Start(); |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 401 | } |
| 402 | |
| 403 | void WebstoreInlineInstaller::InstallUIAbort(bool user_initiated) { |
| 404 | CompleteInstall(kUserCancelledError); |
| 405 | } |
| 406 | |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame^] | 407 | void WebstoreInlineInstaller::WebContentsDestroyed(WebContents* web_contents) { |
[email protected] | 2fd920fb | 2011-09-08 23:33:00 | [diff] [blame] | 408 | // Abort any in-progress fetches. |
| 409 | if (webstore_data_url_fetcher_.get()) { |
| 410 | webstore_data_url_fetcher_.reset(); |
| 411 | Release(); // Matches the AddRef in BeginInstall. |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 412 | } |
[email protected] | 2fd920fb | 2011-09-08 23:33:00 | [diff] [blame] | 413 | } |
| 414 | |
[email protected] | cb08ba2 | 2011-10-19 21:41:40 | [diff] [blame] | 415 | void WebstoreInlineInstaller::OnExtensionInstallSuccess(const std::string& id) { |
| 416 | CHECK_EQ(id_, id); |
| 417 | CompleteInstall(""); |
| 418 | } |
| 419 | |
| 420 | void WebstoreInlineInstaller::OnExtensionInstallFailure( |
| 421 | const std::string& id, const std::string& error) { |
| 422 | CHECK_EQ(id_, id); |
| 423 | CompleteInstall(error); |
| 424 | } |
| 425 | |
[email protected] | 2fd920fb | 2011-09-08 23:33:00 | [diff] [blame] | 426 | void WebstoreInlineInstaller::CompleteInstall(const std::string& error) { |
| 427 | // Only bother responding if there's still a tab contents to send back the |
| 428 | // response to. |
| 429 | if (tab_contents()) { |
| 430 | if (error.empty()) { |
| 431 | delegate_->OnInlineInstallSuccess(install_id_); |
| 432 | } else { |
| 433 | delegate_->OnInlineInstallFailure(install_id_, error); |
| 434 | } |
| 435 | } |
| 436 | |
[email protected] | 8915f34 | 2011-08-29 22:14:37 | [diff] [blame] | 437 | Release(); // Matches the AddRef in BeginInstall. |
| 438 | } |