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 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 core_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(success
, data
);
50 ScriptExecutor::ScriptType script_type
=
51 ShouldInsertCSS() ? ScriptExecutor::CSS
: ScriptExecutor::JAVASCRIPT
;
53 std::string extension_id
;
54 base::FilePath extension_path
;
55 std::string extension_default_locale
;
57 extension_id
= extension()->id();
58 extension_path
= extension()->path();
59 extension()->manifest()->GetString(manifest_keys::kDefaultLocale
,
60 &extension_default_locale
);
63 content::BrowserThread::PostTask(
64 content::BrowserThread::FILE,
66 base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS
,
72 extension_default_locale
));
75 void ExecuteCodeFunction::GetFileURLAndLocalizeCSS(
76 ScriptExecutor::ScriptType script_type
,
77 const std::string
& data
,
78 const std::string
& extension_id
,
79 const base::FilePath
& extension_path
,
80 const std::string
& extension_default_locale
) {
81 std::string localized_data
= data
;
82 // Check if the file is CSS and needs localization.
83 if ((script_type
== ScriptExecutor::CSS
) && !extension_id
.empty() &&
84 (data
.find(MessageBundle::kMessageBegin
) != std::string::npos
)) {
85 scoped_ptr
<SubstitutionMap
> localization_messages(
86 file_util::LoadMessageBundleSubstitutionMap(
87 extension_path
, extension_id
, extension_default_locale
));
89 // We need to do message replacement on the data, so it has to be mutable.
91 MessageBundle::ReplaceMessagesWithExternalDictionary(
92 *localization_messages
, &localized_data
, &error
);
95 file_url_
= net::FilePathToFileURL(resource_
.GetFilePath());
97 // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter
98 // is always true, because if loading had failed, we wouldn't have had
99 // anything to localize.
100 content::BrowserThread::PostTask(
101 content::BrowserThread::UI
,
103 base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile
,
109 void ExecuteCodeFunction::DidLoadAndLocalizeFile(bool success
,
110 const std::string
& data
) {
112 if (!base::IsStringUTF8(data
)) {
113 error_
= ErrorUtils::FormatErrorMessage(
114 kBadFileEncodingError
, resource_
.relative_path().AsUTF8Unsafe());
116 } else if (!Execute(data
))
119 // TODO(viettrungluu): bug: there's no particular reason the path should be
120 // UTF-8, in which case this may fail.
121 error_
= ErrorUtils::FormatErrorMessage(
122 kLoadFileError
, resource_
.relative_path().AsUTF8Unsafe());
127 bool ExecuteCodeFunction::Execute(const std::string
& code_string
) {
128 ScriptExecutor
* executor
= GetScriptExecutor();
135 ScriptExecutor::ScriptType script_type
= ScriptExecutor::JAVASCRIPT
;
136 if (ShouldInsertCSS())
137 script_type
= ScriptExecutor::CSS
;
139 ScriptExecutor::FrameScope frame_scope
=
140 details_
->all_frames
.get() && *details_
->all_frames
141 ? ScriptExecutor::ALL_FRAMES
142 : ScriptExecutor::TOP_FRAME
;
144 ScriptExecutor::MatchAboutBlank match_about_blank
=
145 details_
->match_about_blank
.get() && *details_
->match_about_blank
146 ? ScriptExecutor::MATCH_ABOUT_BLANK
147 : ScriptExecutor::DONT_MATCH_ABOUT_BLANK
;
149 UserScript::RunLocation run_at
= UserScript::UNDEFINED
;
150 switch (details_
->run_at
) {
151 case InjectDetails::RUN_AT_NONE
:
152 case InjectDetails::RUN_AT_DOCUMENT_IDLE
:
153 run_at
= UserScript::DOCUMENT_IDLE
;
155 case InjectDetails::RUN_AT_DOCUMENT_START
:
156 run_at
= UserScript::DOCUMENT_START
;
158 case InjectDetails::RUN_AT_DOCUMENT_END
:
159 run_at
= UserScript::DOCUMENT_END
;
162 CHECK_NE(UserScript::UNDEFINED
, run_at
);
164 executor
->ExecuteScript(
171 ScriptExecutor::ISOLATED_WORLD
,
172 IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS
173 : ScriptExecutor::DEFAULT_PROCESS
,
177 has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT
178 : ScriptExecutor::NO_RESULT
,
179 base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished
, this));
183 bool ExecuteCodeFunction::HasPermission() {
187 bool ExecuteCodeFunction::RunAsync() {
188 EXTENSION_FUNCTION_VALIDATE(Init());
190 if (!details_
->code
.get() && !details_
->file
.get()) {
191 error_
= kNoCodeOrFileToExecuteError
;
194 if (details_
->code
.get() && details_
->file
.get()) {
195 error_
= kMoreThanOneValuesError
;
199 if (!CanExecuteScriptOnPage())
202 if (details_
->code
.get())
203 return Execute(*details_
->code
);
205 if (!details_
->file
.get())
207 resource_
= extension()->GetResource(*details_
->file
);
209 if (resource_
.extension_root().empty() || resource_
.relative_path().empty()) {
210 error_
= kNoCodeOrFileToExecuteError
;
215 const ComponentExtensionResourceManager
*
216 component_extension_resource_manager
=
217 ExtensionsBrowserClient::Get()
218 ->GetComponentExtensionResourceManager();
219 if (component_extension_resource_manager
&&
220 component_extension_resource_manager
->IsComponentExtensionResource(
221 resource_
.extension_root(),
222 resource_
.relative_path(),
224 const ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
225 DidLoadFile(true, rb
.GetRawDataResource(resource_id
).as_string());
227 scoped_refptr
<FileReader
> file_reader(new FileReader(
228 resource_
, base::Bind(&ExecuteCodeFunction::DidLoadFile
, this)));
229 file_reader
->Start();
235 void ExecuteCodeFunction::OnExecuteCodeFinished(const std::string
& error
,
237 const base::ListValue
& result
) {
241 SendResponse(error
.empty());
244 } // namespace extensions
246 #endif // EXTENSIONS_BROWSER_API_EXECUTE_CODE_FUNCTION_IMPL_H_