blob: a32f4c29c76363eb3280dc3b3b63336a5a4261f5 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/webstore_installer.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "googleurl/src/gurl.h"
#include "net/base/escape.h"
namespace {
const char kInvalidIdError[] = "Invalid id";
const char kNoBrowserError[] = "No browser found";
const char kInlineInstallSource[] = "inline";
const char kDefaultInstallSource[] = "";
GURL GetWebstoreInstallURL(
const std::string& extension_id, const std::string& install_source) {
std::vector<std::string> params;
params.push_back("id=" + extension_id);
if (!install_source.empty()) {
params.push_back("installsource=" + install_source);
}
params.push_back("lang=" + g_browser_process->GetApplicationLocale());
params.push_back("uc");
std::string url_string = extension_urls::GetWebstoreUpdateUrl(true).spec();
GURL url(url_string + "?response=redirect&x=" +
net::EscapeQueryParamValue(JoinString(params, '&'), true));
DCHECK(url.is_valid());
return url;
}
} // namespace
WebstoreInstaller::WebstoreInstaller(Profile* profile,
Delegate* delegate,
NavigationController* controller,
const std::string& id,
int flags)
: profile_(profile),
delegate_(delegate),
controller_(controller),
id_(id),
flags_(flags) {
download_url_ = GetWebstoreInstallURL(id, flags & FLAG_INLINE_INSTALL ?
kInlineInstallSource : kDefaultInstallSource);
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
content::Source<Profile>(profile));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
content::Source<CrxInstaller>(NULL));
}
WebstoreInstaller::~WebstoreInstaller() {}
void WebstoreInstaller::Start() {
AddRef(); // Balanced in ReportSuccess and ReportFailure.
if (!Extension::IdIsValid(id_)) {
ReportFailure(kInvalidIdError);
return;
}
// TODO(mihaip): For inline installs, we pretend like the referrer is the
// gallery, even though this could be an inline install, in order to pass the
// checks in ExtensionService::IsDownloadFromGallery. We should instead pass
// the real referrer, track if this is an inline install in the whitelist
// entry and look that up when checking that this is a valid download.
GURL referrer = controller_->GetActiveEntry()->url();
if (flags_ & FLAG_INLINE_INSTALL)
referrer = GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id_);
// The download url for the given extension is contained in |download_url_|.
// We will navigate the current tab to this url to start the download. The
// download system will then pass the crx to the CrxInstaller.
controller_->LoadURL(download_url_,
referrer,
content::PAGE_TRANSITION_LINK,
std::string());
}
void WebstoreInstaller::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
CHECK(profile_->IsSameProfile(content::Source<Profile>(source).ptr()));
const Extension* extension =
content::Details<const Extension>(details).ptr();
if (id_ == extension->id())
ReportSuccess();
break;
}
case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
CrxInstaller* crx_installer = content::Source<CrxInstaller>(source).ptr();
CHECK(crx_installer);
if (!profile_->IsSameProfile(crx_installer->profile()))
return;
const std::string* error =
content::Details<const std::string>(details).ptr();
if (download_url_ == crx_installer->original_download_url())
ReportFailure(*error);
break;
}
default:
NOTREACHED();
}
}
void WebstoreInstaller::ReportFailure(const std::string& error) {
if (delegate_)
delegate_->OnExtensionInstallFailure(id_, error);
Release(); // Balanced in Start().
}
void WebstoreInstaller::ReportSuccess() {
if (delegate_)
delegate_->OnExtensionInstallSuccess(id_);
Release(); // Balanced in Start().
}