1 // Copyright (c) 2013 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/extensions/api/execute_code_function.h"
7 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
8 #include "chrome/browser/extensions/image_loader.h"
9 #include "chrome/browser/extensions/script_executor.h"
10 #include "chrome/common/extensions/api/i18n/default_locale_handler.h"
11 #include "chrome/common/extensions/extension_file_util.h"
12 #include "chrome/common/extensions/extension_messages.h"
13 #include "chrome/common/extensions/message_bundle.h"
14 #include "extensions/browser/file_reader.h"
15 #include "extensions/common/error_utils.h"
16 #include "net/base/net_util.h"
17 #include "ui/base/resource/resource_bundle.h"
19 namespace extensions
{
21 namespace keys
= tabs_constants
;
22 using api::tabs::InjectDetails
;
24 ExecuteCodeFunction::ExecuteCodeFunction() {
27 ExecuteCodeFunction::~ExecuteCodeFunction() {
30 void ExecuteCodeFunction::DidLoadFile(bool success
,
31 const std::string
& data
) {
33 if (!success
|| !details_
->file
) {
34 DidLoadAndLocalizeFile(success
, data
);
38 ScriptExecutor::ScriptType script_type
=
39 ShouldInsertCSS() ? ScriptExecutor::CSS
: ScriptExecutor::JAVASCRIPT
;
41 std::string extension_id
;
42 base::FilePath extension_path
;
43 std::string extension_default_locale
;
44 const Extension
* extension
= GetExtension();
46 extension_id
= extension
->id();
47 extension_path
= extension
->path();
48 extension_default_locale
= LocaleInfo::GetDefaultLocale(extension
);
51 content::BrowserThread::PostTask(
52 content::BrowserThread::FILE, FROM_HERE
,
53 base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS
, this,
58 extension_default_locale
));
61 void ExecuteCodeFunction::GetFileURLAndLocalizeCSS(
62 ScriptExecutor::ScriptType script_type
,
63 const std::string
& data
,
64 const std::string
& extension_id
,
65 const base::FilePath
& extension_path
,
66 const std::string
& extension_default_locale
) {
68 std::string localized_data
= data
;
69 // Check if the file is CSS and needs localization.
70 if ((script_type
== ScriptExecutor::CSS
) &&
71 !extension_id
.empty() &&
72 (data
.find(MessageBundle::kMessageBegin
) != std::string::npos
)) {
73 scoped_ptr
<SubstitutionMap
> localization_messages(
74 extension_file_util::LoadMessageBundleSubstitutionMap(
75 extension_path
, extension_id
, extension_default_locale
));
77 // We need to do message replacement on the data, so it has to be mutable.
79 MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages
,
84 file_url_
= net::FilePathToFileURL(resource_
.GetFilePath());
86 // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter
87 // is always true, because if loading had failed, we wouldn't have had
88 // anything to localize.
89 content::BrowserThread::PostTask(
90 content::BrowserThread::UI
, FROM_HERE
,
91 base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile
, this,
92 true, localized_data
));
95 void ExecuteCodeFunction::DidLoadAndLocalizeFile(bool success
,
96 const std::string
& data
) {
101 // TODO(viettrungluu): bug: there's no particular reason the path should be
102 // UTF-8, in which case this may fail.
103 error_
= ErrorUtils::FormatErrorMessage(keys::kLoadFileError
,
104 resource_
.relative_path().AsUTF8Unsafe());
109 bool ExecuteCodeFunction::Execute(const std::string
& code_string
) {
110 ScriptExecutor
* executor
= GetScriptExecutor();
114 const Extension
* extension
= GetExtension();
118 ScriptExecutor::ScriptType script_type
= ScriptExecutor::JAVASCRIPT
;
119 if (ShouldInsertCSS())
120 script_type
= ScriptExecutor::CSS
;
122 ScriptExecutor::FrameScope frame_scope
=
123 details_
->all_frames
.get() && *details_
->all_frames
?
124 ScriptExecutor::ALL_FRAMES
:
125 ScriptExecutor::TOP_FRAME
;
127 UserScript::RunLocation run_at
=
128 UserScript::UNDEFINED
;
129 switch (details_
->run_at
) {
130 case InjectDetails::RUN_AT_NONE
:
131 case InjectDetails::RUN_AT_DOCUMENT_IDLE
:
132 run_at
= UserScript::DOCUMENT_IDLE
;
134 case InjectDetails::RUN_AT_DOCUMENT_START
:
135 run_at
= UserScript::DOCUMENT_START
;
137 case InjectDetails::RUN_AT_DOCUMENT_END
:
138 run_at
= UserScript::DOCUMENT_END
;
141 CHECK_NE(UserScript::UNDEFINED
, run_at
);
143 executor
->ExecuteScript(
149 ScriptExecutor::ISOLATED_WORLD
,
150 IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS
151 : ScriptExecutor::DEFAULT_PROCESS
,
153 has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT
154 : ScriptExecutor::NO_RESULT
,
155 base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished
, this));
159 bool ExecuteCodeFunction::HasPermission() {
163 bool ExecuteCodeFunction::RunImpl() {
164 EXTENSION_FUNCTION_VALIDATE(Init());
166 if (!details_
->code
.get() && !details_
->file
.get()) {
167 error_
= keys::kNoCodeOrFileToExecuteError
;
170 if (details_
->code
.get() && details_
->file
.get()) {
171 error_
= keys::kMoreThanOneValuesError
;
175 if (!CanExecuteScriptOnPage())
178 if (details_
->code
.get())
179 return Execute(*details_
->code
);
181 if (!details_
->file
.get())
183 resource_
= GetExtension()->GetResource(*details_
->file
);
185 if (resource_
.extension_root().empty() || resource_
.relative_path().empty()) {
186 error_
= keys::kNoCodeOrFileToExecuteError
;
191 if (ImageLoader::IsComponentExtensionResource(
192 resource_
.extension_root(), resource_
.relative_path(),
194 const ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
195 DidLoadFile(true, rb
.GetRawDataResource(resource_id
).as_string());
197 scoped_refptr
<FileReader
> file_reader(new FileReader(
198 resource_
, base::Bind(&ExecuteCodeFunction::DidLoadFile
, this)));
199 file_reader
->Start();
205 void ExecuteCodeFunction::OnExecuteCodeFinished(
206 const std::string
& error
,
209 const base::ListValue
& result
) {
213 SendResponse(error
.empty());
216 } // namespace extensions