Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / execute_code_function.cc
blob0f98df344a75493bfb53590e96ea77806bf2cbba
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 #ifndef EXTENSIONS_BROWSER_API_EXECUTE_CODE_FUNCTION_IMPL_H_
6 #define EXTENSIONS_BROWSER_API_EXECUTE_CODE_FUNCTION_IMPL_H_
8 #include "extensions/browser/api/execute_code_function.h"
10 #include "extensions/browser/component_extension_resource_manager.h"
11 #include "extensions/browser/extensions_browser_client.h"
12 #include "extensions/browser/file_reader.h"
13 #include "extensions/common/error_utils.h"
14 #include "extensions/common/extension_messages.h"
15 #include "extensions/common/file_util.h"
16 #include "extensions/common/manifest_constants.h"
17 #include "extensions/common/message_bundle.h"
18 #include "net/base/filename_util.h"
19 #include "ui/base/resource/resource_bundle.h"
21 namespace {
23 // Error messages
24 const char kNoCodeOrFileToExecuteError[] = "No source code or file specified.";
25 const char kMoreThanOneValuesError[] =
26 "Code and file should not be specified "
27 "at the same time in the second argument.";
28 const char kBadFileEncodingError[] =
29 "Could not load file '*' for content script. It isn't UTF-8 encoded.";
30 const char kLoadFileError[] = "Failed to load file: \"*\". ";
34 namespace extensions {
36 using api::extension_types::InjectDetails;
38 ExecuteCodeFunction::ExecuteCodeFunction() {
41 ExecuteCodeFunction::~ExecuteCodeFunction() {
44 void ExecuteCodeFunction::DidLoadFile(bool success, const std::string& data) {
45 if (!success || !details_->file) {
46 DidLoadAndLocalizeFile(
47 resource_.relative_path().AsUTF8Unsafe(), success, data);
48 return;
51 ScriptExecutor::ScriptType script_type =
52 ShouldInsertCSS() ? ScriptExecutor::CSS : ScriptExecutor::JAVASCRIPT;
54 std::string extension_id;
55 base::FilePath extension_path;
56 std::string extension_default_locale;
57 if (extension()) {
58 extension_id = extension()->id();
59 extension_path = extension()->path();
60 extension()->manifest()->GetString(manifest_keys::kDefaultLocale,
61 &extension_default_locale);
64 content::BrowserThread::PostTask(
65 content::BrowserThread::FILE,
66 FROM_HERE,
67 base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS,
68 this,
69 script_type,
70 data,
71 extension_id,
72 extension_path,
73 extension_default_locale));
76 void ExecuteCodeFunction::GetFileURLAndLocalizeCSS(
77 ScriptExecutor::ScriptType script_type,
78 const std::string& data,
79 const std::string& extension_id,
80 const base::FilePath& extension_path,
81 const std::string& extension_default_locale) {
82 std::string localized_data = data;
83 // Check if the file is CSS and needs localization.
84 if ((script_type == ScriptExecutor::CSS) && !extension_id.empty() &&
85 (data.find(MessageBundle::kMessageBegin) != std::string::npos)) {
86 scoped_ptr<SubstitutionMap> localization_messages(
87 file_util::LoadMessageBundleSubstitutionMap(
88 extension_path, extension_id, extension_default_locale));
90 // We need to do message replacement on the data, so it has to be mutable.
91 std::string error;
92 MessageBundle::ReplaceMessagesWithExternalDictionary(
93 *localization_messages, &localized_data, &error);
96 file_url_ = net::FilePathToFileURL(resource_.GetFilePath());
98 // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter
99 // is always true, because if loading had failed, we wouldn't have had
100 // anything to localize.
101 content::BrowserThread::PostTask(
102 content::BrowserThread::UI,
103 FROM_HERE,
104 base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile,
105 this,
106 resource_.relative_path().AsUTF8Unsafe(),
107 true,
108 localized_data));
111 void ExecuteCodeFunction::DidLoadAndLocalizeFile(const std::string& file,
112 bool success,
113 const std::string& data) {
114 if (success) {
115 if (!base::IsStringUTF8(data)) {
116 error_ = ErrorUtils::FormatErrorMessage(kBadFileEncodingError, file);
117 SendResponse(false);
118 } else if (!Execute(data))
119 SendResponse(false);
120 } else {
121 // TODO(viettrungluu): bug: there's no particular reason the path should be
122 // UTF-8, in which case this may fail.
123 error_ = ErrorUtils::FormatErrorMessage(kLoadFileError, file);
124 SendResponse(false);
128 bool ExecuteCodeFunction::Execute(const std::string& code_string) {
129 ScriptExecutor* executor = GetScriptExecutor();
130 if (!executor)
131 return false;
133 if (!extension() && !IsWebView())
134 return false;
136 ScriptExecutor::ScriptType script_type = ScriptExecutor::JAVASCRIPT;
137 if (ShouldInsertCSS())
138 script_type = ScriptExecutor::CSS;
140 ScriptExecutor::FrameScope frame_scope =
141 details_->all_frames.get() && *details_->all_frames
142 ? ScriptExecutor::ALL_FRAMES
143 : ScriptExecutor::TOP_FRAME;
145 ScriptExecutor::MatchAboutBlank match_about_blank =
146 details_->match_about_blank.get() && *details_->match_about_blank
147 ? ScriptExecutor::MATCH_ABOUT_BLANK
148 : ScriptExecutor::DONT_MATCH_ABOUT_BLANK;
150 UserScript::RunLocation run_at = UserScript::UNDEFINED;
151 switch (details_->run_at) {
152 case api::extension_types::RUN_AT_NONE:
153 case api::extension_types::RUN_AT_DOCUMENT_IDLE:
154 run_at = UserScript::DOCUMENT_IDLE;
155 break;
156 case api::extension_types::RUN_AT_DOCUMENT_START:
157 run_at = UserScript::DOCUMENT_START;
158 break;
159 case api::extension_types::RUN_AT_DOCUMENT_END:
160 run_at = UserScript::DOCUMENT_END;
161 break;
163 CHECK_NE(UserScript::UNDEFINED, run_at);
165 executor->ExecuteScript(
166 host_id_,
167 script_type,
168 code_string,
169 frame_scope,
170 match_about_blank,
171 run_at,
172 ScriptExecutor::ISOLATED_WORLD,
173 IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS
174 : ScriptExecutor::DEFAULT_PROCESS,
175 GetWebViewSrc(),
176 file_url_,
177 user_gesture_,
178 has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT
179 : ScriptExecutor::NO_RESULT,
180 base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished, this));
181 return true;
184 bool ExecuteCodeFunction::HasPermission() {
185 return true;
188 bool ExecuteCodeFunction::RunAsync() {
189 EXTENSION_FUNCTION_VALIDATE(Init());
191 if (!details_->code.get() && !details_->file.get()) {
192 error_ = kNoCodeOrFileToExecuteError;
193 return false;
195 if (details_->code.get() && details_->file.get()) {
196 error_ = kMoreThanOneValuesError;
197 return false;
200 if (!CanExecuteScriptOnPage())
201 return false;
203 if (details_->code.get())
204 return Execute(*details_->code);
206 if (!details_->file.get())
207 return false;
209 return LoadFile(*details_->file);
212 bool ExecuteCodeFunction::LoadFile(const std::string& file) {
213 resource_ = extension()->GetResource(file);
215 if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
216 error_ = kNoCodeOrFileToExecuteError;
217 return false;
220 int resource_id;
221 const ComponentExtensionResourceManager*
222 component_extension_resource_manager =
223 ExtensionsBrowserClient::Get()
224 ->GetComponentExtensionResourceManager();
225 if (component_extension_resource_manager &&
226 component_extension_resource_manager->IsComponentExtensionResource(
227 resource_.extension_root(),
228 resource_.relative_path(),
229 &resource_id)) {
230 const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
231 DidLoadFile(true, rb.GetRawDataResource(resource_id).as_string());
232 } else {
233 scoped_refptr<FileReader> file_reader(new FileReader(
234 resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this)));
235 file_reader->Start();
238 return true;
241 void ExecuteCodeFunction::OnExecuteCodeFinished(const std::string& error,
242 const GURL& on_url,
243 const base::ListValue& result) {
244 if (!error.empty())
245 SetError(error);
247 SendResponse(error.empty());
250 } // namespace extensions
252 #endif // EXTENSIONS_BROWSER_API_EXECUTE_CODE_FUNCTION_IMPL_H_