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"
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 kLoadFileError
[] = "Failed to load file: \"*\". ";
32 namespace extensions
{
34 using core_api::extension_types::InjectDetails
;
36 ExecuteCodeFunction::ExecuteCodeFunction() {
39 ExecuteCodeFunction::~ExecuteCodeFunction() {
42 void ExecuteCodeFunction::DidLoadFile(bool success
, const std::string
& data
) {
43 if (!success
|| !details_
->file
) {
44 DidLoadAndLocalizeFile(success
, data
);
48 ScriptExecutor::ScriptType script_type
=
49 ShouldInsertCSS() ? ScriptExecutor::CSS
: ScriptExecutor::JAVASCRIPT
;
51 std::string extension_id
;
52 base::FilePath extension_path
;
53 std::string extension_default_locale
;
55 extension_id
= extension()->id();
56 extension_path
= extension()->path();
57 extension()->manifest()->GetString(manifest_keys::kDefaultLocale
,
58 &extension_default_locale
);
61 content::BrowserThread::PostTask(
62 content::BrowserThread::FILE,
64 base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS
,
70 extension_default_locale
));
73 void ExecuteCodeFunction::GetFileURLAndLocalizeCSS(
74 ScriptExecutor::ScriptType script_type
,
75 const std::string
& data
,
76 const std::string
& extension_id
,
77 const base::FilePath
& extension_path
,
78 const std::string
& extension_default_locale
) {
79 std::string localized_data
= data
;
80 // Check if the file is CSS and needs localization.
81 if ((script_type
== ScriptExecutor::CSS
) && !extension_id
.empty() &&
82 (data
.find(MessageBundle::kMessageBegin
) != std::string::npos
)) {
83 scoped_ptr
<SubstitutionMap
> localization_messages(
84 file_util::LoadMessageBundleSubstitutionMap(
85 extension_path
, extension_id
, extension_default_locale
));
87 // We need to do message replacement on the data, so it has to be mutable.
89 MessageBundle::ReplaceMessagesWithExternalDictionary(
90 *localization_messages
, &localized_data
, &error
);
93 file_url_
= net::FilePathToFileURL(resource_
.GetFilePath());
95 // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter
96 // is always true, because if loading had failed, we wouldn't have had
97 // anything to localize.
98 content::BrowserThread::PostTask(
99 content::BrowserThread::UI
,
101 base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile
,
107 void ExecuteCodeFunction::DidLoadAndLocalizeFile(bool success
,
108 const std::string
& data
) {
113 // TODO(viettrungluu): bug: there's no particular reason the path should be
114 // UTF-8, in which case this may fail.
115 error_
= ErrorUtils::FormatErrorMessage(
116 kLoadFileError
, resource_
.relative_path().AsUTF8Unsafe());
121 bool ExecuteCodeFunction::Execute(const std::string
& code_string
) {
122 ScriptExecutor
* executor
= GetScriptExecutor();
129 ScriptExecutor::ScriptType script_type
= ScriptExecutor::JAVASCRIPT
;
130 if (ShouldInsertCSS())
131 script_type
= ScriptExecutor::CSS
;
133 ScriptExecutor::FrameScope frame_scope
=
134 details_
->all_frames
.get() && *details_
->all_frames
135 ? ScriptExecutor::ALL_FRAMES
136 : ScriptExecutor::TOP_FRAME
;
138 ScriptExecutor::MatchAboutBlank match_about_blank
=
139 details_
->match_about_blank
.get() && *details_
->match_about_blank
140 ? ScriptExecutor::MATCH_ABOUT_BLANK
141 : ScriptExecutor::DONT_MATCH_ABOUT_BLANK
;
143 UserScript::RunLocation run_at
= UserScript::UNDEFINED
;
144 switch (details_
->run_at
) {
145 case InjectDetails::RUN_AT_NONE
:
146 case InjectDetails::RUN_AT_DOCUMENT_IDLE
:
147 run_at
= UserScript::DOCUMENT_IDLE
;
149 case InjectDetails::RUN_AT_DOCUMENT_START
:
150 run_at
= UserScript::DOCUMENT_START
;
152 case InjectDetails::RUN_AT_DOCUMENT_END
:
153 run_at
= UserScript::DOCUMENT_END
;
156 CHECK_NE(UserScript::UNDEFINED
, run_at
);
158 executor
->ExecuteScript(
165 ScriptExecutor::ISOLATED_WORLD
,
166 IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS
167 : ScriptExecutor::DEFAULT_PROCESS
,
171 has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT
172 : ScriptExecutor::NO_RESULT
,
173 base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished
, this));
177 bool ExecuteCodeFunction::HasPermission() {
181 bool ExecuteCodeFunction::RunAsync() {
182 EXTENSION_FUNCTION_VALIDATE(Init());
184 if (!details_
->code
.get() && !details_
->file
.get()) {
185 error_
= kNoCodeOrFileToExecuteError
;
188 if (details_
->code
.get() && details_
->file
.get()) {
189 error_
= kMoreThanOneValuesError
;
193 if (!CanExecuteScriptOnPage())
196 if (details_
->code
.get())
197 return Execute(*details_
->code
);
199 if (!details_
->file
.get())
201 resource_
= extension()->GetResource(*details_
->file
);
203 if (resource_
.extension_root().empty() || resource_
.relative_path().empty()) {
204 error_
= kNoCodeOrFileToExecuteError
;
209 ComponentExtensionResourceManager
* component_extension_resource_manager
=
210 ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager();
211 if (component_extension_resource_manager
&&
212 component_extension_resource_manager
->IsComponentExtensionResource(
213 resource_
.extension_root(),
214 resource_
.relative_path(),
216 const ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
217 DidLoadFile(true, rb
.GetRawDataResource(resource_id
).as_string());
219 scoped_refptr
<FileReader
> file_reader(new FileReader(
220 resource_
, base::Bind(&ExecuteCodeFunction::DidLoadFile
, this)));
221 file_reader
->Start();
227 void ExecuteCodeFunction::OnExecuteCodeFinished(const std::string
& error
,
229 const base::ListValue
& result
) {
233 SendResponse(error
.empty());
236 } // namespace extensions
238 #endif // EXTENSIONS_BROWSER_API_EXECUTE_CODE_FUNCTION_IMPL_H_