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

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, 8 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 =
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 120
114 WebstoreInstaller::WebstoreInstaller(Profile* profile, 121 WebstoreInstaller::WebstoreInstaller(Profile* profile,
115 Delegate* delegate, 122 Delegate* delegate,
116 NavigationController* controller, 123 NavigationController* controller,
117 const std::string& id, 124 const std::string& id,
118 int flags) 125 int flags)
119 : profile_(profile), 126 : profile_(profile),
120 delegate_(delegate), 127 delegate_(delegate),
121 controller_(controller), 128 controller_(controller),
122 id_(id), 129 id_(id),
130 download_item_(NULL),
123 flags_(flags) { 131 flags_(flags) {
124 download_url_ = GetWebstoreInstallURL(id, flags & FLAG_INLINE_INSTALL ? 132 download_url_ = GetWebstoreInstallURL(id, flags & FLAG_INLINE_INSTALL ?
125 kInlineInstallSource : kDefaultInstallSource); 133 kInlineInstallSource : kDefaultInstallSource);
126 134
135 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE,
136 content::NotificationService::AllSources());
127 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 137 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
128 content::Source<Profile>(profile)); 138 content::Source<Profile>(profile));
129 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, 139 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
130 content::Source<CrxInstaller>(NULL)); 140 content::Source<CrxInstaller>(NULL));
131 } 141 }
132 142
133 WebstoreInstaller::~WebstoreInstaller() {} 143 WebstoreInstaller::~WebstoreInstaller() {
144 RemoveObservers();
145 }
134 146
135 void WebstoreInstaller::Start() { 147 void WebstoreInstaller::Start() {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137 AddRef(); // Balanced in ReportSuccess and ReportFailure. 149 AddRef(); // Balanced in ReportSuccess and ReportFailure.
138 150
139 if (!Extension::IdIsValid(id_)) { 151 if (!Extension::IdIsValid(id_)) {
140 ReportFailure(kInvalidIdError); 152 ReportFailure(kInvalidIdError);
141 return; 153 return;
142 } 154 }
143 155
144 FilePath download_path = DownloadPrefs::FromDownloadManager( 156 FilePath download_path = DownloadPrefs::FromDownloadManager(
145 profile_->GetDownloadManager())->download_path(); 157 profile_->GetDownloadManager())->download_path();
146 BrowserThread::PostTask( 158 BrowserThread::PostTask(
147 BrowserThread::FILE, FROM_HERE, 159 BrowserThread::FILE, FROM_HERE,
148 base::Bind(&GetDownloadFilePath, download_path, id_, 160 base::Bind(&GetDownloadFilePath, download_path, id_,
149 base::Bind(&WebstoreInstaller::StartDownload, 161 base::Bind(&WebstoreInstaller::StartDownload,
150 base::Unretained(this)))); 162 base::Unretained(this))));
151 163
152 } 164 }
153 165
154 void WebstoreInstaller::Observe(int type, 166 void WebstoreInstaller::Observe(int type,
155 const content::NotificationSource& source, 167 const content::NotificationSource& source,
156 const content::NotificationDetails& details) { 168 const content::NotificationDetails& details) {
157 switch (type) { 169 switch (type) {
170 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
171 const Extension* extension =
172 content::Details<const Extension>(details).ptr();
173 const CrxInstaller* installer =
174 content::Source<CrxInstaller>(source).ptr();
175 if (extension == NULL && installer->expected_id() == id_)
Mihai Parparita -not on Chrome 2012/03/26 18:46:49 You may also want to compare installer->profile()
jstritar 2012/03/26 19:53:36 Done. Also switched this to compare the CrxInstall
176 ReportFailure(kInstallCanceledError);
177 break;
178 }
179
158 case chrome::NOTIFICATION_EXTENSION_INSTALLED: { 180 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
159 CHECK(profile_->IsSameProfile(content::Source<Profile>(source).ptr())); 181 CHECK(profile_->IsSameProfile(content::Source<Profile>(source).ptr()));
160 const Extension* extension = 182 const Extension* extension =
161 content::Details<const Extension>(details).ptr(); 183 content::Details<const Extension>(details).ptr();
162 if (id_ == extension->id()) 184 if (id_ == extension->id())
163 ReportSuccess(); 185 ReportSuccess();
164 break; 186 break;
165 } 187 }
166 188
167 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: { 189 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
(...skipping 13 matching lines...) Expand all
181 203
182 default: 204 default:
183 NOTREACHED(); 205 NOTREACHED();
184 } 206 }
185 } 207 }
186 208
187 void WebstoreInstaller::SetDownloadDirectoryForTests(FilePath* directory) { 209 void WebstoreInstaller::SetDownloadDirectoryForTests(FilePath* directory) {
188 g_download_directory_for_tests = directory; 210 g_download_directory_for_tests = directory;
189 } 211 }
190 212
213 void WebstoreInstaller::OnDownloadStarted(DownloadId id, net::Error error) {
214 if (error != net::OK) {
215 ReportFailure(net::ErrorToString(error));
216 return;
217 }
218
219 CHECK(id.IsValid());
220
221 content::DownloadManager* download_manager = profile_->GetDownloadManager();
222 download_item_ = download_manager->GetActiveDownloadItem(id.local());
223 download_item_->AddObserver(this);
224 }
225
226 void WebstoreInstaller::OnDownloadUpdated(DownloadItem* download) {
227 CHECK_EQ(download_item_, download);
228
229 switch (download->GetState()) {
230 case DownloadItem::CANCELLED:
231 ReportFailure(kDownloadCanceledError);
232 break;
233 case DownloadItem::INTERRUPTED:
234 ReportFailure(kDownloadInterruptedError);
235 break;
236 case DownloadItem::REMOVING:
Mihai Parparita -not on Chrome 2012/03/26 18:46:49 Based on what Randy said, it seems cleaner/safer t
jstritar 2012/03/26 19:53:36 Done. I also removed the observer in the destruct
237 break;
238 case DownloadItem::COMPLETE:
239 // Wait for other notifications if the download is really an extension.
240 if (!ChromeDownloadManagerDelegate::IsExtensionDownload(download))
241 ReportFailure(kInvalidDownloadError);
242 break;
243 default:
244 // Continue listening if the download is not in one of the above states.
245 break;
246 }
247 }
248
249 void WebstoreInstaller::OnDownloadOpened(DownloadItem* download) {
250 CHECK_EQ(download_item_, download);
251 }
252
191 void WebstoreInstaller::StartDownload(const FilePath& file) { 253 void WebstoreInstaller::StartDownload(const FilePath& file) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193 255
194 if (file.empty()) { 256 if (file.empty()) {
195 ReportFailure(kDownloadDirectoryError); 257 ReportFailure(kDownloadDirectoryError);
196 return; 258 return;
197 } 259 }
198 260
199 // TODO(mihaip): For inline installs, we pretend like the referrer is the 261 // 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 262 // gallery, even though this could be an inline install, in order to pass the
201 // checks in ExtensionService::IsDownloadFromGallery. We should instead pass 263 // checks in ExtensionService::IsDownloadFromGallery. We should instead pass
202 // the real referrer, track if this is an inline install in the whitelist 264 // 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. 265 // entry and look that up when checking that this is a valid download.
204 GURL referrer = controller_->GetActiveEntry()->GetURL(); 266 GURL referrer = controller_->GetActiveEntry()->GetURL();
205 if (flags_ & FLAG_INLINE_INSTALL) 267 if (flags_ & FLAG_INLINE_INSTALL)
206 referrer = GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id_); 268 referrer = GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id_);
207 269
208 content::DownloadSaveInfo save_info; 270 content::DownloadSaveInfo save_info;
209 save_info.file_path = file; 271 save_info.file_path = file;
210 272
211 // The download url for the given extension is contained in |download_url_|. 273 // 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 274 // 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. 275 // download system will then pass the crx to the CrxInstaller.
214 download_util::RecordDownloadSource( 276 download_util::RecordDownloadSource(
215 download_util::INITIATED_BY_WEBSTORE_INSTALLER); 277 download_util::INITIATED_BY_WEBSTORE_INSTALLER);
216 profile_->GetDownloadManager()->DownloadUrl( 278 profile_->GetDownloadManager()->DownloadUrl(
217 download_url_, referrer, "", 279 download_url_, referrer, "",
218 false, -1, save_info, controller_->GetWebContents(), 280 false, -1, save_info, controller_->GetWebContents(),
219 content::DownloadManager::OnStartedCallback()); 281 base::Bind(&WebstoreInstaller::OnDownloadStarted, this));
220 } 282 }
221 283
222 void WebstoreInstaller::ReportFailure(const std::string& error) { 284 void WebstoreInstaller::ReportFailure(const std::string& error) {
223 if (delegate_) 285 if (delegate_)
224 delegate_->OnExtensionInstallFailure(id_, error); 286 delegate_->OnExtensionInstallFailure(id_, error);
225 287
288 RemoveObservers();
Mihai Parparita -not on Chrome 2012/03/26 18:46:49 This may be obsolete because of the comment above,
jstritar 2012/03/26 19:53:36 Done. I also NULL out the delegat to make sure we
226 Release(); // Balanced in Start(). 289 Release(); // Balanced in Start().
227 } 290 }
228 291
229 void WebstoreInstaller::ReportSuccess() { 292 void WebstoreInstaller::ReportSuccess() {
230 if (delegate_) 293 if (delegate_)
231 delegate_->OnExtensionInstallSuccess(id_); 294 delegate_->OnExtensionInstallSuccess(id_);
232 295
296 RemoveObservers();
Mihai Parparita -not on Chrome 2012/03/26 18:46:49 Ditto.
jstritar 2012/03/26 19:53:36 Done.
233 Release(); // Balanced in Start(). 297 Release(); // Balanced in Start().
234 } 298 }
299
300 void WebstoreInstaller::RemoveObservers() {
301 registrar_.RemoveAll();
302 if (download_item_) {
303 download_item_->RemoveObserver(this);
304 download_item_ = NULL;
305 }
306 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698