| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/webstore_standalone_installer.h" | 5 #include "chrome/browser/extensions/webstore_standalone_installer.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/stringprintf.h" |
| 10 #include "base/string_util.h" | |
| 11 #include "base/values.h" | 10 #include "base/values.h" |
| 12 #include "chrome/browser/browser_process.h" | |
| 13 #include "chrome/browser/extensions/crx_installer.h" | 11 #include "chrome/browser/extensions/crx_installer.h" |
| 14 #include "chrome/browser/extensions/extension_install_ui.h" | 12 #include "chrome/browser/extensions/extension_install_ui.h" |
| 15 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
| 14 #include "chrome/browser/extensions/webstore_data_fetcher.h" |
| 16 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/common/chrome_utility_messages.h" | |
| 18 #include "chrome/common/extensions/extension.h" | 16 #include "chrome/common/extensions/extension.h" |
| 19 #include "chrome/common/extensions/extension_constants.h" | |
| 20 #include "chrome/common/url_constants.h" | |
| 21 #include "content/public/browser/utility_process_host.h" | |
| 22 #include "content/public/browser/utility_process_host_client.h" | |
| 23 #include "content/public/browser/web_contents.h" | 17 #include "content/public/browser/web_contents.h" |
| 24 #include "content/public/browser/web_contents_view.h" | 18 #include "content/public/browser/web_contents_view.h" |
| 25 #include "extensions/common/url_pattern.h" | |
| 26 #include "net/base/escape.h" | |
| 27 #include "net/base/load_flags.h" | |
| 28 #include "net/url_request/url_fetcher.h" | |
| 29 #include "net/url_request/url_request_status.h" | |
| 30 | 19 |
| 31 using content::BrowserThread; | 20 using content::BrowserThread; |
| 32 using content::OpenURLParams; | 21 using content::OpenURLParams; |
| 33 using content::UtilityProcessHost; | |
| 34 using content::UtilityProcessHostClient; | |
| 35 using content::WebContents; | 22 using content::WebContents; |
| 36 | 23 |
| 37 namespace extensions { | 24 namespace extensions { |
| 38 | 25 |
| 39 const char kManifestKey[] = "manifest"; | 26 const char kManifestKey[] = "manifest"; |
| 40 const char kIconUrlKey[] = "icon_url"; | 27 const char kIconUrlKey[] = "icon_url"; |
| 41 const char kLocalizedNameKey[] = "localized_name"; | 28 const char kLocalizedNameKey[] = "localized_name"; |
| 42 const char kLocalizedDescriptionKey[] = "localized_description"; | 29 const char kLocalizedDescriptionKey[] = "localized_description"; |
| 43 const char kUsersKey[] = "users"; | 30 const char kUsersKey[] = "users"; |
| 44 const char kAverageRatingKey[] = "average_rating"; | 31 const char kAverageRatingKey[] = "average_rating"; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 56 const char kNoVerifiedSiteError[] = | 43 const char kNoVerifiedSiteError[] = |
| 57 "Inline installs can only be initiated for Chrome Web Store items that " | 44 "Inline installs can only be initiated for Chrome Web Store items that " |
| 58 "have a verified site"; | 45 "have a verified site"; |
| 59 const char kNotFromVerifiedSiteError[] = | 46 const char kNotFromVerifiedSiteError[] = |
| 60 "Installs can only be initiated by the Chrome Web Store item's verified " | 47 "Installs can only be initiated by the Chrome Web Store item's verified " |
| 61 "site"; | 48 "site"; |
| 62 const char kInlineInstallSupportedError[] = | 49 const char kInlineInstallSupportedError[] = |
| 63 "Inline installation is not supported for this item. The user will be " | 50 "Inline installation is not supported for this item. The user will be " |
| 64 "redirected to the Chrome Web Store."; | 51 "redirected to the Chrome Web Store."; |
| 65 | 52 |
| 66 class SafeWebstoreResponseParser : public UtilityProcessHostClient { | |
| 67 public: | |
| 68 SafeWebstoreResponseParser(WebstoreStandaloneInstaller *client, | |
| 69 const std::string& webstore_data) | |
| 70 : client_(client), | |
| 71 webstore_data_(webstore_data) {} | |
| 72 | |
| 73 void Start() { | |
| 74 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 75 BrowserThread::PostTask( | |
| 76 BrowserThread::IO, | |
| 77 FROM_HERE, | |
| 78 base::Bind(&SafeWebstoreResponseParser::StartWorkOnIOThread, this)); | |
| 79 } | |
| 80 | |
| 81 void StartWorkOnIOThread() { | |
| 82 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 83 UtilityProcessHost* host = | |
| 84 UtilityProcessHost::Create( | |
| 85 this, base::MessageLoopProxy::current()); | |
| 86 host->EnableZygote(); | |
| 87 host->Send(new ChromeUtilityMsg_ParseJSON(webstore_data_)); | |
| 88 } | |
| 89 | |
| 90 // Implementing pieces of the UtilityProcessHostClient interface. | |
| 91 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { | |
| 92 bool handled = true; | |
| 93 IPC_BEGIN_MESSAGE_MAP(SafeWebstoreResponseParser, message) | |
| 94 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded, | |
| 95 OnJSONParseSucceeded) | |
| 96 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed, | |
| 97 OnJSONParseFailed) | |
| 98 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 99 IPC_END_MESSAGE_MAP() | |
| 100 return handled; | |
| 101 } | |
| 102 | |
| 103 void OnJSONParseSucceeded(const ListValue& wrapper) { | |
| 104 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 105 const Value* value = NULL; | |
| 106 CHECK(wrapper.Get(0, &value)); | |
| 107 if (value->IsType(Value::TYPE_DICTIONARY)) { | |
| 108 parsed_webstore_data_.reset( | |
| 109 static_cast<const DictionaryValue*>(value)->DeepCopy()); | |
| 110 } else { | |
| 111 error_ = kInvalidWebstoreResponseError; | |
| 112 } | |
| 113 | |
| 114 ReportResults(); | |
| 115 } | |
| 116 | |
| 117 virtual void OnJSONParseFailed(const std::string& error_message) { | |
| 118 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 119 error_ = error_message; | |
| 120 ReportResults(); | |
| 121 } | |
| 122 | |
| 123 void ReportResults() { | |
| 124 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 125 | |
| 126 BrowserThread::PostTask( | |
| 127 BrowserThread::UI, | |
| 128 FROM_HERE, | |
| 129 base::Bind(&SafeWebstoreResponseParser::ReportResultOnUIThread, this)); | |
| 130 } | |
| 131 | |
| 132 void ReportResultOnUIThread() { | |
| 133 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 134 if (error_.empty() && parsed_webstore_data_.get()) { | |
| 135 client_->OnWebstoreResponseParseSuccess(parsed_webstore_data_.release()); | |
| 136 } else { | |
| 137 client_->OnWebstoreResponseParseFailure(error_); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 private: | |
| 142 virtual ~SafeWebstoreResponseParser() {} | |
| 143 | |
| 144 WebstoreStandaloneInstaller* client_; | |
| 145 | |
| 146 std::string webstore_data_; | |
| 147 std::string error_; | |
| 148 scoped_ptr<DictionaryValue> parsed_webstore_data_; | |
| 149 }; | |
| 150 | |
| 151 WebstoreStandaloneInstaller::WebstoreStandaloneInstaller( | 53 WebstoreStandaloneInstaller::WebstoreStandaloneInstaller( |
| 152 WebContents* web_contents, | 54 WebContents* web_contents, |
| 153 std::string webstore_item_id, | 55 std::string webstore_item_id, |
| 154 VerifiedSiteRequired require_verified_site, | 56 VerifiedSiteRequired require_verified_site, |
| 155 PromptType prompt_type, | 57 PromptType prompt_type, |
| 156 GURL requestor_url, | 58 GURL requestor_url, |
| 157 Callback callback) | 59 Callback callback) |
| 158 : content::WebContentsObserver(web_contents), | 60 : content::WebContentsObserver(web_contents), |
| 159 id_(webstore_item_id), | 61 id_(webstore_item_id), |
| 160 require_verified_site_(require_verified_site == REQUIRE_VERIFIED_SITE), | 62 require_verified_site_(require_verified_site == REQUIRE_VERIFIED_SITE), |
| 161 prompt_type_(prompt_type), | 63 prompt_type_(prompt_type), |
| 162 requestor_url_(requestor_url), | 64 requestor_url_(requestor_url), |
| 163 callback_(callback), | 65 callback_(callback), |
| 164 skip_post_install_ui_(false), | 66 skip_post_install_ui_(false), |
| 165 average_rating_(0.0), | 67 average_rating_(0.0), |
| 166 rating_count_(0) { | 68 rating_count_(0) { |
| 167 CHECK(!callback.is_null()); | 69 CHECK(!callback.is_null()); |
| 168 } | 70 } |
| 169 | 71 |
| 170 void WebstoreStandaloneInstaller::BeginInstall() { | 72 void WebstoreStandaloneInstaller::BeginInstall() { |
| 171 AddRef(); // Balanced in CompleteInstall or WebContentsDestroyed. | 73 AddRef(); // Balanced in CompleteInstall or WebContentsDestroyed. |
| 172 | 74 |
| 173 if (!Extension::IdIsValid(id_)) { | 75 if (!Extension::IdIsValid(id_)) { |
| 174 CompleteInstall(kInvalidWebstoreItemId); | 76 CompleteInstall(kInvalidWebstoreItemId); |
| 175 return; | 77 return; |
| 176 } | 78 } |
| 177 | 79 |
| 178 GURL webstore_data_url(extension_urls::GetWebstoreItemJsonDataURL(id_)); | |
| 179 | |
| 180 webstore_data_url_fetcher_.reset(net::URLFetcher::Create( | |
| 181 webstore_data_url, net::URLFetcher::GET, this)); | |
| 182 Profile* profile = Profile::FromBrowserContext( | 80 Profile* profile = Profile::FromBrowserContext( |
| 183 web_contents()->GetBrowserContext()); | 81 web_contents()->GetBrowserContext()); |
| 184 webstore_data_url_fetcher_->SetRequestContext( | |
| 185 profile->GetRequestContext()); | |
| 186 // Use the requesting page as the referrer both since that is more correct | 82 // Use the requesting page as the referrer both since that is more correct |
| 187 // (it is the page that caused this request to happen) and so that we can | 83 // (it is the page that caused this request to happen) and so that we can |
| 188 // track top sites that trigger inline install requests. | 84 // track top sites that trigger inline install requests. |
| 189 webstore_data_url_fetcher_->SetReferrer(requestor_url_.spec()); | 85 webstore_data_fetcher_.reset(new WebstoreDataFetcher( |
| 190 webstore_data_url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | | 86 this, |
| 191 net::LOAD_DISABLE_CACHE); | 87 profile->GetRequestContext(), |
| 192 webstore_data_url_fetcher_->Start(); | 88 requestor_url_, |
| 89 id_)); |
| 90 webstore_data_fetcher_->Start(); |
| 193 } | 91 } |
| 194 | 92 |
| 195 WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {} | 93 WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {} |
| 196 | 94 |
| 197 void WebstoreStandaloneInstaller::OnURLFetchComplete( | 95 void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() { |
| 198 const net::URLFetcher* source) { | 96 CompleteInstall(kWebstoreRequestError); |
| 199 CHECK_EQ(webstore_data_url_fetcher_.get(), source); | |
| 200 // We shouldn't be getting UrlFetcher callbacks if the WebContents has gone | |
| 201 // away; we stop any in in-progress fetches in WebContentsDestroyed. | |
| 202 CHECK(web_contents()); | |
| 203 | |
| 204 if (!webstore_data_url_fetcher_->GetStatus().is_success() || | |
| 205 webstore_data_url_fetcher_->GetResponseCode() != 200) { | |
| 206 CompleteInstall(kWebstoreRequestError); | |
| 207 return; | |
| 208 } | |
| 209 | |
| 210 std::string webstore_json_data; | |
| 211 webstore_data_url_fetcher_->GetResponseAsString(&webstore_json_data); | |
| 212 webstore_data_url_fetcher_.reset(); | |
| 213 | |
| 214 scoped_refptr<SafeWebstoreResponseParser> parser = | |
| 215 new SafeWebstoreResponseParser(this, webstore_json_data); | |
| 216 // The parser will call us back via OnWebstoreResponseParseSucces or | |
| 217 // OnWebstoreResponseParseFailure. | |
| 218 parser->Start(); | |
| 219 } | 97 } |
| 220 | 98 |
| 221 void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess( | 99 void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess( |
| 222 DictionaryValue* webstore_data) { | 100 DictionaryValue* webstore_data) { |
| 223 // Check if the tab has gone away in the meantime. | 101 // Check if the tab has gone away in the meantime. |
| 224 if (!web_contents()) { | 102 if (!web_contents()) { |
| 225 CompleteInstall(""); | 103 CompleteInstall(""); |
| 226 return; | 104 return; |
| 227 } | 105 } |
| 228 | 106 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 } | 296 } |
| 419 | 297 |
| 420 void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) { | 298 void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) { |
| 421 CompleteInstall(kUserCancelledError); | 299 CompleteInstall(kUserCancelledError); |
| 422 } | 300 } |
| 423 | 301 |
| 424 void WebstoreStandaloneInstaller::WebContentsDestroyed( | 302 void WebstoreStandaloneInstaller::WebContentsDestroyed( |
| 425 WebContents* web_contents) { | 303 WebContents* web_contents) { |
| 426 callback_.Reset(); | 304 callback_.Reset(); |
| 427 // Abort any in-progress fetches. | 305 // Abort any in-progress fetches. |
| 428 if (webstore_data_url_fetcher_.get()) { | 306 if (webstore_data_fetcher_.get()) { |
| 429 webstore_data_url_fetcher_.reset(); | 307 webstore_data_fetcher_.reset(); |
| 430 Release(); // Matches the AddRef in BeginInstall. | 308 Release(); // Matches the AddRef in BeginInstall. |
| 431 } | 309 } |
| 432 } | 310 } |
| 433 | 311 |
| 434 void WebstoreStandaloneInstaller::OnExtensionInstallSuccess( | 312 void WebstoreStandaloneInstaller::OnExtensionInstallSuccess( |
| 435 const std::string& id) { | 313 const std::string& id) { |
| 436 CHECK_EQ(id_, id); | 314 CHECK_EQ(id_, id); |
| 437 CompleteInstall(""); | 315 CompleteInstall(""); |
| 438 } | 316 } |
| 439 | 317 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 DLOG(WARNING) << "Could not parse " << verified_site_url << | 349 DLOG(WARNING) << "Could not parse " << verified_site_url << |
| 472 " as URL pattern " << parse_result; | 350 " as URL pattern " << parse_result; |
| 473 return false; | 351 return false; |
| 474 } | 352 } |
| 475 verified_site_pattern.SetScheme("*"); | 353 verified_site_pattern.SetScheme("*"); |
| 476 | 354 |
| 477 return verified_site_pattern.MatchesURL(requestor_url); | 355 return verified_site_pattern.MatchesURL(requestor_url); |
| 478 } | 356 } |
| 479 | 357 |
| 480 } // namespace extensions | 358 } // namespace extensions |
| OLD | NEW |