Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1052)

Side by Side Diff: chrome/browser/extensions/webstore_inline_installer.cc

Issue 7741037: Add WebstoreInlineInstaller (downloads store data, shows the install UI, and starts the install). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Put webstore response in the right directory. Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/extensions/webstore_inline_installer.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
9 #include "base/string_util.h"
10 #include "base/values.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/extensions/crx_installer.h"
13 #include "chrome/browser/extensions/extension_install_dialog.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/chrome_utility_messages.h"
16 #include "chrome/common/extensions/extension.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "content/browser/tab_contents/tab_contents.h"
19 #include "content/browser/utility_process_host.h"
20 #include "googleurl/src/gurl.h"
21 #include "net/base/escape.h"
22 #include "net/url_request/url_request_status.h"
23
24 const char kManifestKey[] = "manifest";
25 const char kIconUrlKey[] = "icon_url";
26 const char kLocalizedNameKey[] = "localized_name";
27
28 const char kInvalidWebstoreItemId[] = "Invalid webstore item ID";
29 const char kWebstoreRequestError[] = "Could not fetch data from webstore";
30 const char kInvalidWebstoreResponseError[] = "Invalid webstore reponse";
31 const char kInvalidManifestError[] = "Invalid manifest";
32 const char kUserCancelledError[] = "User cancelled install";
33
34 class SafeWebstoreResponseParser : public UtilityProcessHost::Client {
35 public:
36 SafeWebstoreResponseParser(WebstoreInlineInstaller *client,
37 const std::string& webstore_data)
38 : client_(client),
39 webstore_data_(webstore_data),
40 utility_host_(NULL) {}
41
42 void Start() {
43 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
44 BrowserThread::PostTask(
45 BrowserThread::IO,
46 FROM_HERE,
47 NewRunnableMethod(this,
48 &SafeWebstoreResponseParser::StartWorkOnIOThread));
49 }
50
51 void StartWorkOnIOThread() {
52 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
53 utility_host_ = new UtilityProcessHost(this, BrowserThread::IO);
54 utility_host_->Send(new ChromeUtilityMsg_ParseJSON(webstore_data_));
55 }
56
57 // Implementing pieces of the UtilityProcessHost::Client interface.
58 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
59 bool handled = true;
60 IPC_BEGIN_MESSAGE_MAP(SafeWebstoreResponseParser, message)
61 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
62 OnJSONParseSucceeded)
63 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
64 OnJSONParseFailed)
65 IPC_MESSAGE_UNHANDLED(handled = false)
66 IPC_END_MESSAGE_MAP()
67 return handled;
68 }
69
70 void OnJSONParseSucceeded(const ListValue& wrapper) {
71 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
72 Value* value = NULL;
73 CHECK(wrapper.Get(0, &value));
74 if (value->IsType(Value::TYPE_DICTIONARY)) {
75 parsed_webstore_data_.reset(
76 static_cast<DictionaryValue*>(value)->DeepCopy());
77 } else {
78 error_ = kInvalidWebstoreResponseError;
79 }
80
81 ReportResults();
82 }
83
84 virtual void OnJSONParseFailed(const std::string& error_message) {
85 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
86 error_ = error_message;
87 ReportResults();
88 }
89
90 void ReportResults() {
91 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
92
93 // The utility_host_ will take care of deleting itself after this call.
94 utility_host_ = NULL;
95
96 BrowserThread::PostTask(
97 BrowserThread::UI,
98 FROM_HERE,
99 NewRunnableMethod(this,
100 &SafeWebstoreResponseParser::ReportResultOnUIThread));
101 }
102
103 void ReportResultOnUIThread() {
104 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
105 if (error_.empty() && parsed_webstore_data_.get()) {
106 client_->OnWebstoreResponseParseSuccess(parsed_webstore_data_.release());
107 } else {
108 client_->OnWebstoreResponseParseFailure(error_);
109 }
110 }
111
112 private:
113 virtual ~SafeWebstoreResponseParser() {}
114
115 WebstoreInlineInstaller* client_;
116
117 std::string webstore_data_;
118
119 UtilityProcessHost* utility_host_;
120
121 std::string error_;
122 scoped_ptr<DictionaryValue> parsed_webstore_data_;
123 };
124
125 WebstoreInlineInstaller::WebstoreInlineInstaller(TabContents* tab_contents,
126 std::string webstore_item_id,
127 Delegate* delegate)
128 : tab_contents_(tab_contents),
129 id_(webstore_item_id),
130 delegate_(delegate) {}
131
132 WebstoreInlineInstaller::~WebstoreInlineInstaller() {
133 }
134
135 void WebstoreInlineInstaller::BeginInstall() {
136 AddRef(); // Balanced in CompleteInstall.
137
138 if (!Extension::IdIsValid(id_)) {
139 CompleteInstall(kInvalidWebstoreItemId);
140 return;
141 }
142
143 GURL webstore_data_url(extension_urls::GetWebstoreItemJsonDataURL(id_));
144
145 webstore_data_url_fetcher_.reset(
146 new URLFetcher(webstore_data_url, URLFetcher::GET, this));
147 Profile* profile = Profile::FromBrowserContext(
148 tab_contents_->browser_context());
149 webstore_data_url_fetcher_->set_request_context(
150 profile->GetRequestContext());
151 webstore_data_url_fetcher_->Start();
152 }
153
154 void WebstoreInlineInstaller::OnURLFetchComplete(const URLFetcher* source) {
155 CHECK_EQ(webstore_data_url_fetcher_.get(), source);
156
157 if (!webstore_data_url_fetcher_->status().is_success() ||
158 webstore_data_url_fetcher_->response_code() != 200) {
159 CompleteInstall(kWebstoreRequestError);
160 return;
161 }
162
163 std::string webstore_json_data;
164 webstore_data_url_fetcher_->GetResponseAsString(&webstore_json_data);
165 webstore_data_url_fetcher_.reset();
166
167 scoped_refptr<SafeWebstoreResponseParser> parser =
168 new SafeWebstoreResponseParser(this, webstore_json_data);
169 // The parser will call us back via OnWebstoreResponseParseSucces or
170 // OnWebstoreResponseParseFailure.
171 parser->Start();
172 }
173
174 void WebstoreInlineInstaller::OnWebstoreResponseParseSuccess(
175 DictionaryValue* webstore_data) {
176 webstore_data_.reset(webstore_data);
177
178 std::string manifest;
179 if (!webstore_data->GetString(kManifestKey, &manifest)) {
180 CompleteInstall(kInvalidWebstoreResponseError);
181 return;
182 }
183
184 // Localized name is optional.
185 if (webstore_data->HasKey(kLocalizedNameKey) &&
186 !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) {
187 CompleteInstall(kInvalidWebstoreResponseError);
188 return;
189 }
190
191 // Icon URL is optional.
192 GURL icon_url;
193 if (webstore_data->HasKey(kIconUrlKey)) {
194 std::string icon_url_string;
195 if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
196 CompleteInstall(kInvalidWebstoreResponseError);
197 return;
198 }
199 icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
200 icon_url_string);
201 if (!icon_url.is_valid()) {
202 CompleteInstall(kInvalidWebstoreResponseError);
203 return;
204 }
205 }
206
207 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
208 this,
209 manifest,
210 "", // We don't have any icon data.
211 icon_url,
212 Profile::FromBrowserContext(tab_contents_->browser_context())->
213 GetRequestContext());
214 // The helper will call us back via OnWebstoreParseSucces or
215 // OnWebstoreParseFailure.
216 helper->Start();
217 }
218
219 void WebstoreInlineInstaller::OnWebstoreResponseParseFailure(
220 const std::string& error) {
221 CompleteInstall(error);
222 }
223
224 void WebstoreInlineInstaller::OnWebstoreParseSuccess(
225 const SkBitmap& icon,
226 base::DictionaryValue* manifest) {
227 manifest_.reset(manifest);
228 icon_ = icon;
229
230 Profile* profile = Profile::FromBrowserContext(
231 tab_contents_->browser_context());
232 scoped_refptr<Extension> dummy_extension;
233 ShowExtensionInstallDialogForManifest(profile,
234 this,
235 manifest,
236 id_,
237 localized_name_,
238 &icon_,
239 ExtensionInstallUI::INSTALL_PROMPT,
240 &dummy_extension);
241
242 if (!dummy_extension.get()) {
243 CompleteInstall(kInvalidManifestError);
244 return;
245 }
246
247 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
248 }
249
250 void WebstoreInlineInstaller::OnWebstoreParseFailure(
251 InstallHelperResultCode result_code,
252 const std::string& error_message) {
253 CompleteInstall(error_message);
254 }
255
256 void WebstoreInlineInstaller::InstallUIProceed() {
257 CrxInstaller::WhitelistEntry* entry = new CrxInstaller::WhitelistEntry;
258
259 entry->parsed_manifest.reset(manifest_.get()->DeepCopy());
260 entry->localized_name = localized_name_;
261 entry->use_app_installed_bubble = true;
262 CrxInstaller::SetWhitelistEntry(id_, entry);
263
264 GURL install_url(extension_urls::GetWebstoreInstallUrl(
265 id_, g_browser_process->GetApplicationLocale()));
266
267 NavigationController& controller = tab_contents_->controller();
268 // TODO(mihaip): we pretend like the referrer is the gallery in order to pass
269 // the checks in ExtensionService::IsDownloadFromGallery. We should instead
270 // pass the real referrer, track that this is an inline install in the
271 // whitelist entry and look that up when checking that this is a valid
272 // download.
273 GURL referrer(extension_urls::GetWebstoreItemDetailURLPrefix() + id_);
274 controller.LoadURL(install_url, referrer, PageTransition::LINK);
275
276 // TODO(mihaip): the success message should happen later, when the extension
277 // is actually downloaded and installed (when NOTIFICATION_EXTENSION_INSTALLED
278 // or NOTIFICATION_EXTENSION_INSTALL_ERROR fire).
279 CompleteInstall("");
280 }
281
282 void WebstoreInlineInstaller::InstallUIAbort(bool user_initiated) {
283 CompleteInstall(kUserCancelledError);
284 }
285
286 void WebstoreInlineInstaller::CompleteInstall(const std::string& error) {
287 if (error.empty()) {
288 delegate_->OnInlineInstallSuccess();
289 } else {
290 delegate_->OnInlineInstallFailure(error);
291 }
292 Release(); // Matches the AddRef in BeginInstall.
293 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/webstore_inline_installer.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698