Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / extensions / extension_loader_handler.cc
1 // Copyright 2014 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/ui/webui/extensions/extension_loader_handler.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/extensions/unpacked_installer.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/chrome_select_file_policy.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/user_metrics.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_ui.h"
23 #include "content/public/browser/web_ui_data_source.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/browser/file_highlighter.h"
26 #include "extensions/common/constants.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/manifest_constants.h"
29 #include "grit/generated_resources.h"
30 #include "third_party/re2/re2/re2.h"
31 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/shell_dialogs/select_file_dialog.h"
33
34 namespace extensions {
35
36 namespace {
37
38 // Read a file to a string and return.
39 std::string ReadFileToString(const base::FilePath& path) {
40   std::string data;
41   // This call can fail, but it doesn't matter for our purposes. If it fails,
42   // we simply return an empty string for the manifest, and ignore it.
43   base::ReadFileToString(path, &data);
44   return data;
45 }
46
47 }  // namespace
48
49 class ExtensionLoaderHandler::FileHelper
50     : public ui::SelectFileDialog::Listener {
51  public:
52   explicit FileHelper(ExtensionLoaderHandler* loader_handler);
53   virtual ~FileHelper();
54
55   // Create a FileDialog for the user to select the unpacked extension
56   // directory.
57   void ChooseFile();
58
59  private:
60   // ui::SelectFileDialog::Listener implementation.
61   virtual void FileSelected(const base::FilePath& path,
62                             int index,
63                             void* params) OVERRIDE;
64   virtual void MultiFilesSelected(
65       const std::vector<base::FilePath>& files, void* params) OVERRIDE;
66
67   // The associated ExtensionLoaderHandler. Weak, but guaranteed to be alive,
68   // as it owns this object.
69   ExtensionLoaderHandler* loader_handler_;
70
71   // The dialog used to pick a directory when loading an unpacked extension.
72   scoped_refptr<ui::SelectFileDialog> load_extension_dialog_;
73
74   // The last selected directory, so we can start in the same spot.
75   base::FilePath last_unpacked_directory_;
76
77   // The title of the dialog.
78   base::string16 title_;
79
80   DISALLOW_COPY_AND_ASSIGN(FileHelper);
81 };
82
83 ExtensionLoaderHandler::FileHelper::FileHelper(
84     ExtensionLoaderHandler* loader_handler)
85     : loader_handler_(loader_handler),
86       title_(l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY)) {
87 }
88
89 ExtensionLoaderHandler::FileHelper::~FileHelper() {
90   // There may be a pending file dialog; inform it the listener is destroyed so
91   // it doesn't try and call back.
92   if (load_extension_dialog_.get())
93     load_extension_dialog_->ListenerDestroyed();
94 }
95
96 void ExtensionLoaderHandler::FileHelper::ChooseFile() {
97   static const int kFileTypeIndex = 0;  // No file type information to index.
98   static const ui::SelectFileDialog::Type kSelectType =
99       ui::SelectFileDialog::SELECT_FOLDER;
100
101   if (!load_extension_dialog_.get()) {
102     load_extension_dialog_ = ui::SelectFileDialog::Create(
103         this,
104         new ChromeSelectFilePolicy(
105             loader_handler_->web_ui()->GetWebContents()));
106   }
107
108   load_extension_dialog_->SelectFile(
109       kSelectType,
110       title_,
111       last_unpacked_directory_,
112       NULL,
113       kFileTypeIndex,
114       base::FilePath::StringType(),
115       loader_handler_->web_ui()->GetWebContents()->GetTopLevelNativeWindow(),
116       NULL);
117
118   content::RecordComputedAction("Options_LoadUnpackedExtension");
119 }
120
121 void ExtensionLoaderHandler::FileHelper::FileSelected(
122     const base::FilePath& path, int index, void* params) {
123   loader_handler_->LoadUnpackedExtensionImpl(path);
124 }
125
126 void ExtensionLoaderHandler::FileHelper::MultiFilesSelected(
127       const std::vector<base::FilePath>& files, void* params) {
128   NOTREACHED();
129 }
130
131 ExtensionLoaderHandler::ExtensionLoaderHandler(Profile* profile)
132     : profile_(profile),
133       file_helper_(new FileHelper(this)),
134       weak_ptr_factory_(this) {
135   DCHECK(profile_);
136 }
137
138 ExtensionLoaderHandler::~ExtensionLoaderHandler() {
139 }
140
141 void ExtensionLoaderHandler::GetLocalizedValues(
142     content::WebUIDataSource* source) {
143   source->AddString(
144       "extensionLoadErrorHeading",
145       l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_HEADING));
146   source->AddString(
147       "extensionLoadErrorMessage",
148       l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_MESSAGE));
149   source->AddString(
150       "extensionLoadErrorRetry",
151       l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_RETRY));
152   source->AddString(
153       "extensionLoadErrorGiveUp",
154       l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_GIVE_UP));
155   source->AddString(
156       "extensionLoadCouldNotLoadManifest",
157       l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_COULD_NOT_LOAD_MANIFEST));
158 }
159
160 void ExtensionLoaderHandler::RegisterMessages() {
161   web_ui()->RegisterMessageCallback(
162       "extensionLoaderLoadUnpacked",
163       base::Bind(&ExtensionLoaderHandler::HandleLoadUnpacked,
164                  weak_ptr_factory_.GetWeakPtr()));
165   web_ui()->RegisterMessageCallback(
166       "extensionLoaderRetry",
167       base::Bind(&ExtensionLoaderHandler::HandleRetry,
168                  weak_ptr_factory_.GetWeakPtr()));
169 }
170
171 void ExtensionLoaderHandler::HandleLoadUnpacked(const base::ListValue* args) {
172   DCHECK(args->empty());
173   file_helper_->ChooseFile();
174 }
175
176 void ExtensionLoaderHandler::HandleRetry(const base::ListValue* args) {
177   DCHECK(args->empty());
178   LoadUnpackedExtensionImpl(failed_path_);
179 }
180
181 void ExtensionLoaderHandler::LoadUnpackedExtensionImpl(
182     const base::FilePath& file_path) {
183   scoped_refptr<UnpackedInstaller> installer = UnpackedInstaller::Create(
184       ExtensionSystem::Get(profile_)->extension_service());
185   installer->set_on_failure_callback(
186       base::Bind(&ExtensionLoaderHandler::OnLoadFailure,
187                  weak_ptr_factory_.GetWeakPtr()));
188
189   // We do our own error handling, so we don't want a load failure to trigger
190   // a dialog.
191   installer->set_be_noisy_on_failure(false);
192
193   installer->Load(file_path);
194 }
195
196 void ExtensionLoaderHandler::OnLoadFailure(const base::FilePath& file_path,
197                                            const std::string& error) {
198   failed_path_ = file_path;
199   size_t line = 0u;
200   size_t column = 0u;
201   std::string regex =
202       base::StringPrintf("%s  Line: (\\d+), column: (\\d+), Syntax error.",
203                          manifest_errors::kManifestParseError);
204   // If this was a JSON parse error, we can highlight the exact line with the
205   // error. Otherwise, we should still display the manifest (for consistency,
206   // reference, and so that if we ever make this really fancy and add an editor,
207   // it's ready).
208   //
209   // This regex call can fail, but if it does, we just don't highlight anything.
210   re2::RE2::FullMatch(error, regex, &line, &column);
211
212   // This will read the manifest and call NotifyFrontendOfFailure with the read
213   // manifest contents.
214   base::PostTaskAndReplyWithResult(
215       content::BrowserThread::GetBlockingPool(),
216       FROM_HERE,
217       base::Bind(&ReadFileToString, file_path.Append(kManifestFilename)),
218       base::Bind(&ExtensionLoaderHandler::NotifyFrontendOfFailure,
219                  weak_ptr_factory_.GetWeakPtr(),
220                  file_path,
221                  error,
222                  line));
223 }
224
225 void ExtensionLoaderHandler::NotifyFrontendOfFailure(
226     const base::FilePath& file_path,
227     const std::string& error,
228     size_t line_number,
229     const std::string& manifest) {
230   base::StringValue file_value(file_path.LossyDisplayName());
231   base::StringValue error_value(base::UTF8ToUTF16(error));
232
233   base::DictionaryValue manifest_value;
234   SourceHighlighter highlighter(manifest, line_number);
235   // If the line number is 0, this highlights no regions, but still adds the
236   // full manifest.
237   highlighter.SetHighlightedRegions(&manifest_value);
238
239   web_ui()->CallJavascriptFunction(
240       "extensions.ExtensionLoader.notifyLoadFailed",
241       file_value,
242       error_value,
243       manifest_value);
244 }
245
246 }  // namespace extensions