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 |