15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be
35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file.
45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/webui/extensions/extension_loader_handler.h"
65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/bind.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/logging.h"
105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/memory/ref_counted.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/string16.h"
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/string_util.h"
135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/stringprintf.h"
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/utf_string_conversions.h"
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/extensions/path_util.h"
165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/extensions/unpacked_installer.h"
176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/extensions/zipfile_installer.h"
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/profiles/profile.h"
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/chrome_select_file_policy.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h"
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/browser/browser_thread.h"
225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/browser/user_metrics.h"
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/browser/web_contents.h"
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/browser/web_ui.h"
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/browser/web_ui_data_source.h"
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/browser/extension_system.h"
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/browser/file_highlighter.h"
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/common/constants.h"
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/common/extension.h"
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/common/manifest_constants.h"
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "third_party/re2/re2/re2.h"
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/base/l10n/l10n_util.h"
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/shell_dialogs/select_file_dialog.h"
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace extensions {
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace {
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Read a file to a string and return.
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustd::string ReadFileToString(const base::FilePath& path) {
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::string data;
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // This call can fail, but it doesn't matter for our purposes. If it fails,
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // we simply return an empty string for the manifest, and ignore it.
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::ReadFileToString(path, &data);
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return data;
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}  // namespace
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass ExtensionLoaderHandler::FileHelper
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : public ui::SelectFileDialog::Listener {
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  explicit FileHelper(ExtensionLoaderHandler* loader_handler);
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual ~FileHelper();
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Create a FileDialog for the user to select the unpacked extension
575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // directory.
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void ChooseFile();
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // ui::SelectFileDialog::Listener implementation.
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void FileSelected(const base::FilePath& path,
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                            int index,
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                            void* params) OVERRIDE;
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void MultiFilesSelected(
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const std::vector<base::FilePath>& files, void* params) OVERRIDE;
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The associated ExtensionLoaderHandler. Weak, but guaranteed to be alive,
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // as it owns this object.
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ExtensionLoaderHandler* loader_handler_;
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The dialog used to pick a directory when loading an unpacked extension.
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_refptr<ui::SelectFileDialog> load_extension_dialog_;
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The last selected directory, so we can start in the same spot.
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::FilePath last_unpacked_directory_;
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The title of the dialog.
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::string16 title_;
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(FileHelper);
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuExtensionLoaderHandler::FileHelper::FileHelper(
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ExtensionLoaderHandler* loader_handler)
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : loader_handler_(loader_handler),
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      title_(l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY)) {
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuExtensionLoaderHandler::FileHelper::~FileHelper() {
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // There may be a pending file dialog; inform it the listener is destroyed so
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // it doesn't try and call back.
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (load_extension_dialog_.get())
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    load_extension_dialog_->ListenerDestroyed();
955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ExtensionLoaderHandler::FileHelper::ChooseFile() {
985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  static const int kFileTypeIndex = 0;  // No file type information to index.
995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  static const ui::SelectFileDialog::Type kSelectType =
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ui::SelectFileDialog::SELECT_FOLDER;
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!load_extension_dialog_.get()) {
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    load_extension_dialog_ = ui::SelectFileDialog::Create(
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        this,
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        new ChromeSelectFilePolicy(
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            loader_handler_->web_ui()->GetWebContents()));
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  load_extension_dialog_->SelectFile(
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      kSelectType,
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      title_,
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      last_unpacked_directory_,
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      NULL,
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      kFileTypeIndex,
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::FilePath::StringType(),
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      loader_handler_->web_ui()->GetWebContents()->GetTopLevelNativeWindow(),
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      NULL);
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  content::RecordComputedAction("Options_LoadUnpackedExtension");
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ExtensionLoaderHandler::FileHelper::FileSelected(
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const base::FilePath& path, int index, void* params) {
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  loader_handler_->LoadUnpackedExtensionImpl(path);
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ExtensionLoaderHandler::FileHelper::MultiFilesSelected(
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const std::vector<base::FilePath>& files, void* params) {
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  NOTREACHED();
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuExtensionLoaderHandler::ExtensionLoaderHandler(Profile* profile)
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : profile_(profile),
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      file_helper_(new FileHelper(this)),
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension_error_reporter_observer_(this),
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ui_ready_(false),
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      weak_ptr_factory_(this) {
1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(profile_);
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  extension_error_reporter_observer_.Add(ExtensionErrorReporter::GetInstance());
1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuExtensionLoaderHandler::~ExtensionLoaderHandler() {
1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ExtensionLoaderHandler::GetLocalizedValues(
1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    content::WebUIDataSource* source) {
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  source->AddString(
1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "extensionLoadErrorHeading",
1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_HEADING));
1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  source->AddString(
1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "extensionLoadErrorMessage",
1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_MESSAGE));
1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  source->AddString(
1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "extensionLoadErrorRetry",
1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_RETRY));
1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  source->AddString(
1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "extensionLoadErrorGiveUp",
1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_GIVE_UP));
1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  source->AddString(
1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "extensionLoadCouldNotLoadManifest",
1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_COULD_NOT_LOAD_MANIFEST));
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  source->AddString(
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      "extensionLoadAdditionalFailures",
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ADDITIONAL_FAILURES));
1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ExtensionLoaderHandler::RegisterMessages() {
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // We observe WebContents in order to detect page refreshes, since notifying
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // the frontend of load failures must be delayed until the page finishes
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // loading. We never call Observe(NULL) because this object is constructed
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // on page load and persists between refreshes.
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  content::WebContentsObserver::Observe(web_ui()->GetWebContents());
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  web_ui()->RegisterMessageCallback(
1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "extensionLoaderLoadUnpacked",
1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::Bind(&ExtensionLoaderHandler::HandleLoadUnpacked,
1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 weak_ptr_factory_.GetWeakPtr()));
1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  web_ui()->RegisterMessageCallback(
1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "extensionLoaderRetry",
1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::Bind(&ExtensionLoaderHandler::HandleRetry,
1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 weak_ptr_factory_.GetWeakPtr()));
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_ui()->RegisterMessageCallback(
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      "extensionLoaderIgnoreFailure",
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&ExtensionLoaderHandler::HandleIgnoreFailure,
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 weak_ptr_factory_.GetWeakPtr()));
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_ui()->RegisterMessageCallback(
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      "extensionLoaderDisplayFailures",
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&ExtensionLoaderHandler::HandleDisplayFailures,
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 weak_ptr_factory_.GetWeakPtr()));
1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ExtensionLoaderHandler::HandleLoadUnpacked(const base::ListValue* args) {
1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(args->empty());
1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  file_helper_->ChooseFile();
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ExtensionLoaderHandler::HandleRetry(const base::ListValue* args) {
1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(args->empty());
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const base::FilePath file_path = failed_paths_.back();
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  failed_paths_.pop_back();
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LoadUnpackedExtensionImpl(file_path);
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ExtensionLoaderHandler::HandleIgnoreFailure(const base::ListValue* args) {
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(args->empty());
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  failed_paths_.pop_back();
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ExtensionLoaderHandler::HandleDisplayFailures(
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::ListValue* args) {
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(args->empty());
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ui_ready_ = true;
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Notify the frontend of any load failures that were triggered while the
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // chrome://extensions page was loading.
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!failures_.empty())
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    NotifyFrontendOfFailure();
2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ExtensionLoaderHandler::LoadUnpackedExtensionImpl(
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const base::FilePath& file_path) {
2225b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  scoped_refptr<UnpackedInstaller> installer = UnpackedInstaller::Create(
2235b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      ExtensionSystem::Get(profile_)->extension_service());
2245b892326406927b709cdaf6c384d4ababf456332Ben Murdoch
2255b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  // We do our own error handling, so we don't want a load failure to trigger
2265b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  // a dialog.
2275b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  installer->set_be_noisy_on_failure(false);
2285b892326406927b709cdaf6c384d4ababf456332Ben Murdoch
2295b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  installer->Load(file_path);
2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionLoaderHandler::OnLoadFailure(
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content::BrowserContext* browser_context,
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const base::FilePath& file_path,
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& error) {
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Only show errors from our browser context.
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (web_ui()->GetWebContents()->GetBrowserContext() != browser_context)
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  size_t line = 0u;
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  size_t column = 0u;
2425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::string regex =
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::StringPrintf("%s  Line: (\\d+), column: (\\d+), .*",
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         manifest_errors::kManifestParseError);
2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // If this was a JSON parse error, we can highlight the exact line with the
2465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // error. Otherwise, we should still display the manifest (for consistency,
2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // reference, and so that if we ever make this really fancy and add an editor,
2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // it's ready).
2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  //
2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // This regex call can fail, but if it does, we just don't highlight anything.
2515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  re2::RE2::FullMatch(error, regex, &line, &column);
2525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // This will read the manifest and call AddFailure with the read manifest
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // contents.
2555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::PostTaskAndReplyWithResult(
2565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      content::BrowserThread::GetBlockingPool(),
2575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      FROM_HERE,
2585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::Bind(&ReadFileToString, file_path.Append(kManifestFilename)),
259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&ExtensionLoaderHandler::AddFailure,
2605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 weak_ptr_factory_.GetWeakPtr(),
2615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 file_path,
2625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 error,
2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 line));
2645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ExtensionLoaderHandler::DidStartNavigationToPendingEntry(
267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const GURL& url,
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::NavigationController::ReloadType reload_type) {
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // In the event of a page reload, we ensure that the frontend is not notified
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // until the UI finishes loading, so we set |ui_ready_| to false. This is
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // balanced in HandleDisplayFailures, which is called when the frontend is
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // ready to receive failure notifications.
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (reload_type != content::NavigationController::NO_RELOAD)
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ui_ready_ = false;
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ExtensionLoaderHandler::AddFailure(
2785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const base::FilePath& file_path,
2795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& error,
2805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    size_t line_number,
2815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& manifest) {
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  failed_paths_.push_back(file_path);
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath prettified_path = path_util::PrettifyPath(file_path);
2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<base::DictionaryValue> manifest_value(new base::DictionaryValue());
2865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SourceHighlighter highlighter(manifest, line_number);
2875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // If the line number is 0, this highlights no regions, but still adds the
2885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // full manifest.
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  highlighter.SetHighlightedRegions(manifest_value.get());
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<base::DictionaryValue> failure(new base::DictionaryValue());
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  failure->Set("path",
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch               new base::StringValue(prettified_path.LossyDisplayName()));
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  failure->Set("error", new base::StringValue(base::UTF8ToUTF16(error)));
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  failure->Set("manifest", manifest_value.release());
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  failures_.Append(failure.release());
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Only notify the frontend if the frontend UI is ready.
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (ui_ready_)
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    NotifyFrontendOfFailure();
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
3025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ExtensionLoaderHandler::NotifyFrontendOfFailure() {
3045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  web_ui()->CallJavascriptFunction(
3055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "extensions.ExtensionLoader.notifyLoadFailed",
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      failures_);
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  failures_.Clear();
3085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}  // namespace extensions
311