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