blob: 13f8e73afee84f95ee8298aa7ee07a2a71d1f864 [file] [log] [blame]
[email protected]655b2b1a2011-10-13 17:13:061// 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_installer.h"
6
7#include "chrome/browser/browser_process.h"
8#include "chrome/browser/extensions/crx_installer.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/tabs/tab_strip_model.h"
11#include "chrome/browser/ui/browser_list.h"
12#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
13#include "chrome/common/chrome_notification_types.h"
14#include "chrome/common/extensions/extension.h"
15#include "content/browser/tab_contents/navigation_controller.h"
16#include "content/common/notification_details.h"
17#include "content/common/notification_source.h"
18#include "googleurl/src/gurl.h"
19
20namespace {
21
22const char kInvalidIdError[] = "Invalid id";
23const char kNoBrowserError[] = "No browser found";
24
25} // namespace
26
27
28WebstoreInstaller::WebstoreInstaller(Profile* profile)
29 : profile_(profile) {
30 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
31 Source<Profile>(profile));
32 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
33 Source<CrxInstaller>(NULL));
34}
35
36WebstoreInstaller::~WebstoreInstaller() {}
37
38struct WebstoreInstaller::PendingInstall {
39 PendingInstall() : delegate(NULL) {}
40 PendingInstall(const std::string& id, const GURL& url, Delegate* delegate)
41 : id(id), download_url(url), delegate(delegate) {}
42 ~PendingInstall() {}
43
44 // The id of the extension.
45 std::string id;
46
47 // The gallery download URL for the extension.
48 GURL download_url;
49
50 // The delegate for this install.
51 Delegate* delegate;
52};
53
54void WebstoreInstaller::InstallExtension(
55 const std::string& id, Delegate* delegate, int flags) {
56 if (!Extension::IdIsValid(id)) {
57 ReportFailure(id, kInvalidIdError);
58 return;
59 }
60
61 Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
62 if (!browser) {
63 ReportFailure(id, kNoBrowserError);
64 return;
65 }
66
67 PendingInstall pending_install = CreatePendingInstall(id, delegate);
68
69 // The download url for the given |id| is now contained in
70 // |pending_install.download_url|. We navigate the current tab to this url
71 // which will result in a download starting. Once completed it will go through
72 // the normal extension install flow.
73 NavigationController& controller =
74 browser->tabstrip_model()->GetActiveTabContents()->controller();
75
76 // TODO(mihaip, jstritar): For inline installs, we pretend like the referrer
77 // is the gallery, even though this could be an inline install, in order to
78 // pass the checks in ExtensionService::IsDownloadFromGallery. We should
79 // instead pass the real referrer, track if this is an inline install in the
80 // whitelist entry and look that up when checking that this is a valid
81 // download.
82 GURL referrer = controller.GetActiveEntry()->url();
83 if (flags & FLAG_OVERRIDE_REFERRER)
84 referrer = GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id);
85
86 controller.LoadURL(pending_install.download_url,
87 referrer,
88 content::PAGE_TRANSITION_LINK,
89 std::string());
90}
91
92void WebstoreInstaller::Observe(int type,
93 const NotificationSource& source,
94 const NotificationDetails& details) {
95 switch (type) {
96 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
97 CHECK(profile_->IsSameProfile(Source<Profile>(source).ptr()));
98 const Extension* extension = Details<const Extension>(details).ptr();
99 ReportSuccess(extension->id());
100 break;
101 }
102
103 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
104 CrxInstaller* crx_installer = Source<CrxInstaller>(source).ptr();
105 CHECK(crx_installer);
106 if (!profile_->IsSameProfile(crx_installer->profile()))
107 return;
108
109 std::string id = GetPendingInstallId(
110 crx_installer->original_download_url());
111 const std::string* error = Details<const std::string>(details).ptr();
112 if (!id.empty())
113 ReportFailure(id, *error);
114 break;
115 }
116
117 default:
118 NOTREACHED();
119 }
120}
121
122bool WebstoreInstaller::ClearPendingInstall(
123 const std::string& id, PendingInstall* install) {
124 for (size_t i = 0; i < pending_installs_.size(); ++i) {
125 if (pending_installs_[i].id == id) {
126 *install = pending_installs_[i];
127 pending_installs_.erase(pending_installs_.begin() + i);
128 return true;
129 }
130 }
131 return false;
132}
133
134const WebstoreInstaller::PendingInstall&
135 WebstoreInstaller::CreatePendingInstall(
136 const std::string& id, Delegate* delegate) {
137 GURL install_url = extension_urls::GetWebstoreInstallUrl(
138 id, g_browser_process->GetApplicationLocale());
139
140 PendingInstall pending_install(id, install_url, delegate);
141 pending_installs_.push_back(pending_install);
142
143 return *(pending_installs_.end() - 1);
144}
145
146
147std::string WebstoreInstaller::GetPendingInstallId(const GURL& url) {
148 if (url.is_empty())
149 return std::string();
150
151 for (size_t i = 0; i < pending_installs_.size(); ++i) {
152 if (pending_installs_[i].download_url == url)
153 return pending_installs_[i].id;
154 }
155
156 return std::string();
157}
158
159void WebstoreInstaller::ReportFailure(
160 const std::string& id, const std::string& error) {
161 PendingInstall install;
162 if (!ClearPendingInstall(id, &install))
163 return;
164
165 if (install.delegate)
166 install.delegate->OnExtensionInstallFailure(id, error);
167}
168
169void WebstoreInstaller::ReportSuccess(const std::string& id) {
170 PendingInstall install;
171 if (!ClearPendingInstall(id, &install))
172 return;
173
174 if (install.delegate)
175 install.delegate->OnExtensionInstallSuccess(id);
176}