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

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

Issue 9837054: Improve WebstoreInstaller error handling. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 9 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
OLDNEW
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_installer.h" 5 #include "chrome/browser/extensions/webstore_installer.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/rand_util.h" 11 #include "base/rand_util.h"
12 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
13 #include "base/string_util.h" 13 #include "base/string_util.h"
14 #include "base/string_number_conversions.h" 14 #include "base/string_number_conversions.h"
15 #include "base/utf_string_conversions.h" 15 #include "base/utf_string_conversions.h"
16 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/download/chrome_download_manager_delegate.h"
17 #include "chrome/browser/download/download_prefs.h" 18 #include "chrome/browser/download/download_prefs.h"
18 #include "chrome/browser/download/download_util.h" 19 #include "chrome/browser/download/download_util.h"
19 #include "chrome/browser/extensions/crx_installer.h" 20 #include "chrome/browser/extensions/crx_installer.h"
20 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/tabs/tab_strip_model.h" 22 #include "chrome/browser/tabs/tab_strip_model.h"
22 #include "chrome/browser/ui/browser_list.h" 23 #include "chrome/browser/ui/browser_list.h"
23 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 24 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
24 #include "chrome/common/chrome_notification_types.h" 25 #include "chrome/common/chrome_notification_types.h"
25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/extensions/extension.h" 27 #include "chrome/common/extensions/extension.h"
27 #include "chrome/common/extensions/extension_constants.h" 28 #include "chrome/common/extensions/extension_constants.h"
28 #include "content/public/browser/browser_thread.h" 29 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/download_manager.h" 30 #include "content/public/browser/download_manager.h"
30 #include "content/public/browser/download_save_info.h" 31 #include "content/public/browser/download_save_info.h"
31 #include "content/public/browser/navigation_controller.h" 32 #include "content/public/browser/navigation_controller.h"
32 #include "content/public/browser/navigation_entry.h" 33 #include "content/public/browser/navigation_entry.h"
33 #include "content/public/browser/notification_details.h" 34 #include "content/public/browser/notification_details.h"
35 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/notification_source.h" 36 #include "content/public/browser/notification_source.h"
35 #include "googleurl/src/gurl.h" 37 #include "googleurl/src/gurl.h"
36 #include "net/base/escape.h" 38 #include "net/base/escape.h"
37 39
38 using content::BrowserThread; 40 using content::BrowserThread;
41 using content::DownloadId;
42 using content::DownloadItem;
39 using content::NavigationController; 43 using content::NavigationController;
40 44
41 namespace { 45 namespace {
42 46
43 const char kInvalidIdError[] = "Invalid id"; 47 const char kInvalidIdError[] = "Invalid id";
44 const char kNoBrowserError[] = "No browser found"; 48 const char kNoBrowserError[] = "No browser found";
45 const char kDownloadDirectoryError[] = "Could not create download directory"; 49 const char kDownloadDirectoryError[] = "Could not create download directory";
46 50 const char kDownloadCanceledError[] = "Download canceled";
51 const char kInstallCanceledError[] = "Install canceled";
52 const char kDownloadInterruptedError[] = "Download interrupted";
53 const char kInvalidDownloadError[] = "Download was not a CRX";
47 const char kInlineInstallSource[] = "inline"; 54 const char kInlineInstallSource[] = "inline";
48 const char kDefaultInstallSource[] = ""; 55 const char kDefaultInstallSource[] = "";
49 56
50 FilePath* g_download_directory_for_tests = NULL; 57 FilePath* g_download_directory_for_tests = NULL;
51 58
52 GURL GetWebstoreInstallURL( 59 GURL GetWebstoreInstallURL(
53 const std::string& extension_id, const std::string& install_source) { 60 const std::string& extension_id, const std::string& install_source) {
54 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 61 CommandLine* cmd_line = CommandLine::ForCurrentProcess();
55 if (cmd_line->HasSwitch(switches::kAppsGalleryDownloadURL)) { 62 if (cmd_line->HasSwitch(switches::kAppsGalleryDownloadURL)) {
56 std::string download_url = 63 std::string download_url =
57 cmd_line->GetSwitchValueASCII(switches::kAppsGalleryDownloadURL); 64 cmd_line->GetSwitchValueASCII(switches::kAppsGalleryDownloadURL);
58 return GURL(base::StringPrintf(download_url.c_str(), 65 return GURL(base::StringPrintf(download_url.c_str(),
59 extension_id.c_str())); 66 extension_id.c_str()));
60 } 67 }
61 std::vector<std::string> params; 68 std::vector<std::string> params;
62 params.push_back("id=" + extension_id); 69 params.push_back("id=" + extension_id);
63 if (!install_source.empty()) { 70 if (!install_source.empty())
64 params.push_back("installsource=" + install_source); 71 params.push_back("installsource=" + install_source);
65 }
66 params.push_back("lang=" + g_browser_process->GetApplicationLocale()); 72 params.push_back("lang=" + g_browser_process->GetApplicationLocale());
67 params.push_back("uc"); 73 params.push_back("uc");
68 std::string url_string = extension_urls::GetWebstoreUpdateUrl(true).spec(); 74 std::string url_string = extension_urls::GetWebstoreUpdateUrl(true).spec();
69 75
70 GURL url(url_string + "?response=redirect&x=" + 76 GURL url(url_string + "?response=redirect&x=" +
71 net::EscapeQueryParamValue(JoinString(params, '&'), true)); 77 net::EscapeQueryParamValue(JoinString(params, '&'), true));
72 DCHECK(url.is_valid()); 78 DCHECK(url.is_valid());
73 79
74 return url; 80 return url;
75 } 81 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 119
114 WebstoreInstaller::WebstoreInstaller(Profile* profile, 120 WebstoreInstaller::WebstoreInstaller(Profile* profile,
115 Delegate* delegate, 121 Delegate* delegate,
116 NavigationController* controller, 122 NavigationController* controller,
117 const std::string& id, 123 const std::string& id,
118 int flags) 124 int flags)
119 : profile_(profile), 125 : profile_(profile),
120 delegate_(delegate), 126 delegate_(delegate),
121 controller_(controller), 127 controller_(controller),
122 id_(id), 128 id_(id),
129 download_item_(NULL),
123 flags_(flags) { 130 flags_(flags) {
124 download_url_ = GetWebstoreInstallURL(id, flags & FLAG_INLINE_INSTALL ? 131 download_url_ = GetWebstoreInstallURL(id, flags & FLAG_INLINE_INSTALL ?
125 kInlineInstallSource : kDefaultInstallSource); 132 kInlineInstallSource : kDefaultInstallSource);
126 133
134 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE,
135 content::NotificationService::AllSources());
127 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 136 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
128 content::Source<Profile>(profile)); 137 content::Source<Profile>(profile));
129 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, 138 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
130 content::Source<CrxInstaller>(NULL)); 139 content::Source<CrxInstaller>(NULL));
131 } 140 }
132 141
133 WebstoreInstaller::~WebstoreInstaller() {} 142 WebstoreInstaller::~WebstoreInstaller() {
143 if (download_item_) {
144 download_item_->RemoveObserver(this);
145 download_item_ = NULL;
146 }
147 }
134 148
135 void WebstoreInstaller::Start() { 149 void WebstoreInstaller::Start() {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137 AddRef(); // Balanced in ReportSuccess and ReportFailure. 151 AddRef(); // Balanced in ReportSuccess and ReportFailure.
138 152
139 if (!Extension::IdIsValid(id_)) { 153 if (!Extension::IdIsValid(id_)) {
140 ReportFailure(kInvalidIdError); 154 ReportFailure(kInvalidIdError);
141 return; 155 return;
142 } 156 }
143 157
144 FilePath download_path = DownloadPrefs::FromDownloadManager( 158 FilePath download_path = DownloadPrefs::FromDownloadManager(
145 profile_->GetDownloadManager())->download_path(); 159 profile_->GetDownloadManager())->download_path();
146 BrowserThread::PostTask( 160 BrowserThread::PostTask(
147 BrowserThread::FILE, FROM_HERE, 161 BrowserThread::FILE, FROM_HERE,
148 base::Bind(&GetDownloadFilePath, download_path, id_, 162 base::Bind(&GetDownloadFilePath, download_path, id_,
149 base::Bind(&WebstoreInstaller::StartDownload, 163 base::Bind(&WebstoreInstaller::StartDownload,
150 base::Unretained(this)))); 164 base::Unretained(this))));
151 165
152 } 166 }
153 167
154 void WebstoreInstaller::Observe(int type, 168 void WebstoreInstaller::Observe(int type,
155 const content::NotificationSource& source, 169 const content::NotificationSource& source,
156 const content::NotificationDetails& details) { 170 const content::NotificationDetails& details) {
157 switch (type) { 171 switch (type) {
172 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
173 const Extension* extension =
174 content::Details<const Extension>(details).ptr();
175 CrxInstaller* installer = content::Source<CrxInstaller>(source).ptr();
176 if (extension == NULL && download_item_ != NULL &&
177 installer->download_url() == download_item_->GetURL() &&
178 installer->profile()->IsSameProfile(profile_)) {
179 ReportFailure(kInstallCanceledError);
180 }
181 break;
182 }
183
158 case chrome::NOTIFICATION_EXTENSION_INSTALLED: { 184 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
159 CHECK(profile_->IsSameProfile(content::Source<Profile>(source).ptr())); 185 CHECK(profile_->IsSameProfile(content::Source<Profile>(source).ptr()));
160 const Extension* extension = 186 const Extension* extension =
161 content::Details<const Extension>(details).ptr(); 187 content::Details<const Extension>(details).ptr();
162 if (id_ == extension->id()) 188 if (id_ == extension->id())
163 ReportSuccess(); 189 ReportSuccess();
164 break; 190 break;
165 } 191 }
166 192
167 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: { 193 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
(...skipping 13 matching lines...) Expand all
181 207
182 default: 208 default:
183 NOTREACHED(); 209 NOTREACHED();
184 } 210 }
185 } 211 }
186 212
187 void WebstoreInstaller::SetDownloadDirectoryForTests(FilePath* directory) { 213 void WebstoreInstaller::SetDownloadDirectoryForTests(FilePath* directory) {
188 g_download_directory_for_tests = directory; 214 g_download_directory_for_tests = directory;
189 } 215 }
190 216
217 void WebstoreInstaller::OnDownloadStarted(DownloadId id, net::Error error) {
218 if (error != net::OK) {
219 ReportFailure(net::ErrorToString(error));
220 return;
221 }
222
223 CHECK(id.IsValid());
224
225 content::DownloadManager* download_manager = profile_->GetDownloadManager();
226 download_item_ = download_manager->GetActiveDownloadItem(id.local());
227 download_item_->AddObserver(this);
228 }
229
230 void WebstoreInstaller::OnDownloadUpdated(DownloadItem* download) {
231 CHECK_EQ(download_item_, download);
232
233 switch (download->GetState()) {
234 case DownloadItem::CANCELLED:
235 ReportFailure(kDownloadCanceledError);
236 break;
237 case DownloadItem::INTERRUPTED:
238 ReportFailure(kDownloadInterruptedError);
239 break;
240 case DownloadItem::REMOVING:
241 download_item_->RemoveObserver(this);
242 download_item_ = NULL;
243 break;
244 case DownloadItem::COMPLETE:
245 // Wait for other notifications if the download is really an extension.
246 if (!ChromeDownloadManagerDelegate::IsExtensionDownload(download))
247 ReportFailure(kInvalidDownloadError);
248 break;
249 default:
250 // Continue listening if the download is not in one of the above states.
251 break;
252 }
253 }
254
255 void WebstoreInstaller::OnDownloadOpened(DownloadItem* download) {
256 CHECK_EQ(download_item_, download);
257 }
258
191 void WebstoreInstaller::StartDownload(const FilePath& file) { 259 void WebstoreInstaller::StartDownload(const FilePath& file) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193 261
194 if (file.empty()) { 262 if (file.empty()) {
195 ReportFailure(kDownloadDirectoryError); 263 ReportFailure(kDownloadDirectoryError);
196 return; 264 return;
197 } 265 }
198 266
199 // TODO(mihaip): For inline installs, we pretend like the referrer is the 267 // TODO(mihaip): For inline installs, we pretend like the referrer is the
200 // gallery, even though this could be an inline install, in order to pass the 268 // gallery, even though this could be an inline install, in order to pass the
201 // checks in ExtensionService::IsDownloadFromGallery. We should instead pass 269 // checks in ExtensionService::IsDownloadFromGallery. We should instead pass
202 // the real referrer, track if this is an inline install in the whitelist 270 // the real referrer, track if this is an inline install in the whitelist
203 // entry and look that up when checking that this is a valid download. 271 // entry and look that up when checking that this is a valid download.
204 GURL referrer = controller_->GetActiveEntry()->GetURL(); 272 GURL referrer = controller_->GetActiveEntry()->GetURL();
205 if (flags_ & FLAG_INLINE_INSTALL) 273 if (flags_ & FLAG_INLINE_INSTALL)
206 referrer = GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id_); 274 referrer = GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id_);
207 275
208 content::DownloadSaveInfo save_info; 276 content::DownloadSaveInfo save_info;
209 save_info.file_path = file; 277 save_info.file_path = file;
210 278
211 // The download url for the given extension is contained in |download_url_|. 279 // The download url for the given extension is contained in |download_url_|.
212 // We will navigate the current tab to this url to start the download. The 280 // We will navigate the current tab to this url to start the download. The
213 // download system will then pass the crx to the CrxInstaller. 281 // download system will then pass the crx to the CrxInstaller.
214 download_util::RecordDownloadSource( 282 download_util::RecordDownloadSource(
215 download_util::INITIATED_BY_WEBSTORE_INSTALLER); 283 download_util::INITIATED_BY_WEBSTORE_INSTALLER);
216 profile_->GetDownloadManager()->DownloadUrl( 284 profile_->GetDownloadManager()->DownloadUrl(
217 download_url_, referrer, "", 285 download_url_, referrer, "",
218 false, -1, save_info, controller_->GetWebContents(), 286 false, -1, save_info, controller_->GetWebContents(),
219 content::DownloadManager::OnStartedCallback()); 287 base::Bind(&WebstoreInstaller::OnDownloadStarted, this));
220 } 288 }
221 289
222 void WebstoreInstaller::ReportFailure(const std::string& error) { 290 void WebstoreInstaller::ReportFailure(const std::string& error) {
223 if (delegate_) 291 if (delegate_) {
224 delegate_->OnExtensionInstallFailure(id_, error); 292 delegate_->OnExtensionInstallFailure(id_, error);
293 delegate_ = NULL;
294 }
225 295
226 Release(); // Balanced in Start(). 296 Release(); // Balanced in Start().
227 } 297 }
228 298
229 void WebstoreInstaller::ReportSuccess() { 299 void WebstoreInstaller::ReportSuccess() {
230 if (delegate_) 300 if (delegate_) {
231 delegate_->OnExtensionInstallSuccess(id_); 301 delegate_->OnExtensionInstallSuccess(id_);
302 delegate_ = NULL;
303 }
232 304
233 Release(); // Balanced in Start(). 305 Release(); // Balanced in Start().
234 } 306 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/webstore_installer.h ('k') | chrome/browser/ui/intents/web_intent_picker_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698