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 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
);
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
;
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,
67 base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS
,
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.
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
,
104 base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile
,
106 resource_
.relative_path().AsUTF8Unsafe(),
111 void ExecuteCodeFunction::DidLoadAndLocalizeFile(const std::string
& file
,
113 const std::string
& data
) {
115 if (!base::IsStringUTF8(data
)) {
116 error_
= ErrorUtils::FormatErrorMessage(kBadFileEncodingError
, file
);
118 } else if (!Execute(data
))
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
);
128 bool ExecuteCodeFunction::Execute(const std::string
& code_string
) {
129 ScriptExecutor
* executor
= GetScriptExecutor();
133 if (!extension() && !IsWebView())
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
;
156 case api::extension_types::RUN_AT_DOCUMENT_START
:
157 run_at
= UserScript::DOCUMENT_START
;
159 case api::extension_types::RUN_AT_DOCUMENT_END
:
160 run_at
= UserScript::DOCUMENT_END
;
163 CHECK_NE(UserScript::UNDEFINED
, run_at
);
165 executor
->ExecuteScript(
172 ScriptExecutor::ISOLATED_WORLD
,
173 IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS
174 : ScriptExecutor::DEFAULT_PROCESS
,
178 has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT
179 : ScriptExecutor::NO_RESULT
,
180 base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished
, this));
184 bool ExecuteCodeFunction::HasPermission() {
188 bool ExecuteCodeFunction::RunAsync() {
189 EXTENSION_FUNCTION_VALIDATE(Init());
191 if (!details_
->code
.get() && !details_
->file
.get()) {
192 error_
= kNoCodeOrFileToExecuteError
;
195 if (details_
->code
.get() && details_
->file
.get()) {
196 error_
= kMoreThanOneValuesError
;
200 if (!CanExecuteScriptOnPage())
203 if (details_
->code
.get())
204 return Execute(*details_
->code
);
206 if (!details_
->file
.get())
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
;
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(),
230 const ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
231 DidLoadFile(true, rb
.GetRawDataResource(resource_id
).as_string());
233 scoped_refptr
<FileReader
> file_reader(new FileReader(
234 resource_
, base::Bind(&ExecuteCodeFunction::DidLoadFile
, this)));
235 file_reader
->Start();
241 void ExecuteCodeFunction::OnExecuteCodeFinished(const std::string
& error
,
243 const base::ListValue
& result
) {
247 SendResponse(error
.empty());
250 } // namespace extensions
252 #endif // EXTENSIONS_BROWSER_API_EXECUTE_CODE_FUNCTION_IMPL_H_