Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / ui / webui / extensions / extension_loader_handler.cc
blob05584e43e30b897192d73198c8d02e1f329dc978
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.
5 #include "chrome/browser/ui/webui/extensions/extension_loader_handler.h"
7 #include "base/bind.h"
8 #include "base/files/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 "chrome/browser/extensions/path_util.h"
16 #include "chrome/browser/extensions/unpacked_installer.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_ui.h"
22 #include "content/public/browser/web_ui_data_source.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/browser/file_highlighter.h"
25 #include "extensions/common/constants.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/manifest_constants.h"
28 #include "third_party/re2/re2/re2.h"
29 #include "ui/base/l10n/l10n_util.h"
31 namespace extensions {
33 namespace {
35 // Read a file to a string and return.
36 std::string ReadFileToString(const base::FilePath& path) {
37 std::string data;
38 // This call can fail, but it doesn't matter for our purposes. If it fails,
39 // we simply return an empty string for the manifest, and ignore it.
40 base::ReadFileToString(path, &data);
41 return data;
44 } // namespace
46 ExtensionLoaderHandler::ExtensionLoaderHandler(Profile* profile)
47 : profile_(profile),
48 extension_error_reporter_observer_(this),
49 ui_ready_(false),
50 weak_ptr_factory_(this) {
51 DCHECK(profile_);
52 extension_error_reporter_observer_.Add(ExtensionErrorReporter::GetInstance());
55 ExtensionLoaderHandler::~ExtensionLoaderHandler() {
58 void ExtensionLoaderHandler::GetLocalizedValues(
59 content::WebUIDataSource* source) {
60 source->AddString(
61 "extensionLoadErrorHeading",
62 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_HEADING));
63 source->AddString(
64 "extensionLoadErrorMessage",
65 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_MESSAGE));
66 source->AddString(
67 "extensionLoadErrorRetry",
68 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_RETRY));
69 source->AddString(
70 "extensionLoadErrorGiveUp",
71 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_GIVE_UP));
72 source->AddString(
73 "extensionLoadCouldNotLoadManifest",
74 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_COULD_NOT_LOAD_MANIFEST));
75 source->AddString(
76 "extensionLoadAdditionalFailures",
77 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ADDITIONAL_FAILURES));
80 void ExtensionLoaderHandler::RegisterMessages() {
81 // We observe WebContents in order to detect page refreshes, since notifying
82 // the frontend of load failures must be delayed until the page finishes
83 // loading. We never call Observe(NULL) because this object is constructed
84 // on page load and persists between refreshes.
85 content::WebContentsObserver::Observe(web_ui()->GetWebContents());
87 web_ui()->RegisterMessageCallback(
88 "extensionLoaderRetry",
89 base::Bind(&ExtensionLoaderHandler::HandleRetry,
90 weak_ptr_factory_.GetWeakPtr()));
91 web_ui()->RegisterMessageCallback(
92 "extensionLoaderIgnoreFailure",
93 base::Bind(&ExtensionLoaderHandler::HandleIgnoreFailure,
94 weak_ptr_factory_.GetWeakPtr()));
95 web_ui()->RegisterMessageCallback(
96 "extensionLoaderDisplayFailures",
97 base::Bind(&ExtensionLoaderHandler::HandleDisplayFailures,
98 weak_ptr_factory_.GetWeakPtr()));
101 void ExtensionLoaderHandler::HandleRetry(const base::ListValue* args) {
102 DCHECK(args->empty());
103 const base::FilePath file_path = failed_paths_.back();
104 failed_paths_.pop_back();
105 LoadUnpackedExtension(file_path);
108 void ExtensionLoaderHandler::HandleIgnoreFailure(const base::ListValue* args) {
109 DCHECK(args->empty());
110 failed_paths_.pop_back();
113 void ExtensionLoaderHandler::HandleDisplayFailures(
114 const base::ListValue* args) {
115 DCHECK(args->empty());
116 ui_ready_ = true;
118 // Notify the frontend of any load failures that were triggered while the
119 // chrome://extensions page was loading.
120 if (!failures_.empty())
121 NotifyFrontendOfFailure();
124 void ExtensionLoaderHandler::LoadUnpackedExtension(
125 const base::FilePath& file_path) {
126 scoped_refptr<UnpackedInstaller> installer = UnpackedInstaller::Create(
127 ExtensionSystem::Get(profile_)->extension_service());
129 // We do our own error handling, so we don't want a load failure to trigger
130 // a dialog.
131 installer->set_be_noisy_on_failure(false);
133 installer->Load(file_path);
136 void ExtensionLoaderHandler::OnLoadFailure(
137 content::BrowserContext* browser_context,
138 const base::FilePath& file_path,
139 const std::string& error) {
140 // Only show errors from our browser context.
141 if (web_ui()->GetWebContents()->GetBrowserContext() != browser_context)
142 return;
144 size_t line = 0u;
145 size_t column = 0u;
146 std::string regex =
147 base::StringPrintf("%s Line: (\\d+), column: (\\d+), .*",
148 manifest_errors::kManifestParseError);
149 // If this was a JSON parse error, we can highlight the exact line with the
150 // error. Otherwise, we should still display the manifest (for consistency,
151 // reference, and so that if we ever make this really fancy and add an editor,
152 // it's ready).
154 // This regex call can fail, but if it does, we just don't highlight anything.
155 re2::RE2::FullMatch(error, regex, &line, &column);
157 // This will read the manifest and call AddFailure with the read manifest
158 // contents.
159 base::PostTaskAndReplyWithResult(
160 content::BrowserThread::GetBlockingPool(),
161 FROM_HERE,
162 base::Bind(&ReadFileToString, file_path.Append(kManifestFilename)),
163 base::Bind(&ExtensionLoaderHandler::AddFailure,
164 weak_ptr_factory_.GetWeakPtr(),
165 file_path,
166 error,
167 line));
170 void ExtensionLoaderHandler::DidStartNavigationToPendingEntry(
171 const GURL& url,
172 content::NavigationController::ReloadType reload_type) {
173 // In the event of a page reload, we ensure that the frontend is not notified
174 // until the UI finishes loading, so we set |ui_ready_| to false. This is
175 // balanced in HandleDisplayFailures, which is called when the frontend is
176 // ready to receive failure notifications.
177 if (reload_type != content::NavigationController::NO_RELOAD)
178 ui_ready_ = false;
181 void ExtensionLoaderHandler::AddFailure(
182 const base::FilePath& file_path,
183 const std::string& error,
184 size_t line_number,
185 const std::string& manifest) {
186 failed_paths_.push_back(file_path);
187 base::FilePath prettified_path = path_util::PrettifyPath(file_path);
189 scoped_ptr<base::DictionaryValue> manifest_value(new base::DictionaryValue());
190 SourceHighlighter highlighter(manifest, line_number);
191 // If the line number is 0, this highlights no regions, but still adds the
192 // full manifest.
193 highlighter.SetHighlightedRegions(manifest_value.get());
195 scoped_ptr<base::DictionaryValue> failure(new base::DictionaryValue());
196 failure->Set("path",
197 new base::StringValue(prettified_path.LossyDisplayName()));
198 failure->Set("error", new base::StringValue(base::UTF8ToUTF16(error)));
199 failure->Set("manifest", manifest_value.release());
200 failures_.Append(failure.release());
202 // Only notify the frontend if the frontend UI is ready.
203 if (ui_ready_)
204 NotifyFrontendOfFailure();
207 void ExtensionLoaderHandler::NotifyFrontendOfFailure() {
208 web_ui()->CallJavascriptFunction(
209 "extensions.ExtensionLoader.notifyLoadFailed",
210 failures_);
211 failures_.Clear();
214 } // namespace extensions