• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/extensions/api/execute_code_function.h"
6 
7 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
8 #include "chrome/browser/extensions/script_executor.h"
9 #include "chrome/common/extensions/api/i18n/default_locale_handler.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/message_bundle.h"
17 #include "net/base/filename_util.h"
18 #include "ui/base/resource/resource_bundle.h"
19 
20 namespace extensions {
21 
22 namespace keys = tabs_constants;
23 using api::tabs::InjectDetails;
24 
ExecuteCodeFunction()25 ExecuteCodeFunction::ExecuteCodeFunction() {
26 }
27 
~ExecuteCodeFunction()28 ExecuteCodeFunction::~ExecuteCodeFunction() {
29 }
30 
DidLoadFile(bool success,const std::string & data)31 void ExecuteCodeFunction::DidLoadFile(bool success,
32                                       const std::string& data) {
33 
34   if (!success || !details_->file) {
35     DidLoadAndLocalizeFile(success, data);
36     return;
37   }
38 
39   ScriptExecutor::ScriptType script_type =
40       ShouldInsertCSS() ? ScriptExecutor::CSS : ScriptExecutor::JAVASCRIPT;
41 
42   std::string extension_id;
43   base::FilePath extension_path;
44   std::string extension_default_locale;
45   const Extension* extension = GetExtension();
46   if (extension) {
47     extension_id = extension->id();
48     extension_path = extension->path();
49     extension_default_locale = LocaleInfo::GetDefaultLocale(extension);
50   }
51 
52   content::BrowserThread::PostTask(
53       content::BrowserThread::FILE, FROM_HERE,
54       base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS, this,
55                   script_type,
56                   data,
57                   extension_id,
58                   extension_path,
59                   extension_default_locale));
60 }
61 
GetFileURLAndLocalizeCSS(ScriptExecutor::ScriptType script_type,const std::string & data,const std::string & extension_id,const base::FilePath & extension_path,const std::string & extension_default_locale)62 void ExecuteCodeFunction::GetFileURLAndLocalizeCSS(
63     ScriptExecutor::ScriptType script_type,
64     const std::string& data,
65     const std::string& extension_id,
66     const base::FilePath& extension_path,
67     const std::string& extension_default_locale) {
68 
69   std::string localized_data = data;
70   // Check if the file is CSS and needs localization.
71   if ((script_type == ScriptExecutor::CSS) &&
72       !extension_id.empty() &&
73       (data.find(MessageBundle::kMessageBegin) != std::string::npos)) {
74     scoped_ptr<SubstitutionMap> localization_messages(
75         file_util::LoadMessageBundleSubstitutionMap(
76             extension_path, extension_id, extension_default_locale));
77 
78     // We need to do message replacement on the data, so it has to be mutable.
79     std::string error;
80     MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages,
81                                                          &localized_data,
82                                                          &error);
83   }
84 
85   file_url_ = net::FilePathToFileURL(resource_.GetFilePath());
86 
87   // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter
88   // is always true, because if loading had failed, we wouldn't have had
89   // anything to localize.
90   content::BrowserThread::PostTask(
91       content::BrowserThread::UI, FROM_HERE,
92       base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this,
93                  true, localized_data));
94 }
95 
DidLoadAndLocalizeFile(bool success,const std::string & data)96 void ExecuteCodeFunction::DidLoadAndLocalizeFile(bool success,
97                                                  const std::string& data) {
98   if (success) {
99     if (!Execute(data))
100       SendResponse(false);
101   } else {
102     // TODO(viettrungluu): bug: there's no particular reason the path should be
103     // UTF-8, in which case this may fail.
104     error_ = ErrorUtils::FormatErrorMessage(keys::kLoadFileError,
105         resource_.relative_path().AsUTF8Unsafe());
106     SendResponse(false);
107   }
108 }
109 
Execute(const std::string & code_string)110 bool ExecuteCodeFunction::Execute(const std::string& code_string) {
111   ScriptExecutor* executor = GetScriptExecutor();
112   if (!executor)
113     return false;
114 
115   const Extension* extension = GetExtension();
116   if (!extension)
117     return false;
118 
119   ScriptExecutor::ScriptType script_type = ScriptExecutor::JAVASCRIPT;
120   if (ShouldInsertCSS())
121     script_type = ScriptExecutor::CSS;
122 
123   ScriptExecutor::FrameScope frame_scope =
124       details_->all_frames.get() && *details_->all_frames ?
125           ScriptExecutor::ALL_FRAMES :
126           ScriptExecutor::TOP_FRAME;
127 
128   ScriptExecutor::MatchAboutBlank match_about_blank =
129       details_->match_about_blank.get() && *details_->match_about_blank ?
130           ScriptExecutor::MATCH_ABOUT_BLANK :
131           ScriptExecutor::DONT_MATCH_ABOUT_BLANK;
132 
133   UserScript::RunLocation run_at =
134       UserScript::UNDEFINED;
135   switch (details_->run_at) {
136     case InjectDetails::RUN_AT_NONE:
137     case InjectDetails::RUN_AT_DOCUMENT_IDLE:
138       run_at = UserScript::DOCUMENT_IDLE;
139       break;
140     case InjectDetails::RUN_AT_DOCUMENT_START:
141       run_at = UserScript::DOCUMENT_START;
142       break;
143     case InjectDetails::RUN_AT_DOCUMENT_END:
144       run_at = UserScript::DOCUMENT_END;
145       break;
146   }
147   CHECK_NE(UserScript::UNDEFINED, run_at);
148 
149   executor->ExecuteScript(
150       extension->id(),
151       script_type,
152       code_string,
153       frame_scope,
154       match_about_blank,
155       run_at,
156       ScriptExecutor::ISOLATED_WORLD,
157       IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS
158                   : ScriptExecutor::DEFAULT_PROCESS,
159       GetWebViewSrc(),
160       file_url_,
161       user_gesture_,
162       has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT
163                      : ScriptExecutor::NO_RESULT,
164       base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished, this));
165   return true;
166 }
167 
HasPermission()168 bool ExecuteCodeFunction::HasPermission() {
169   return true;
170 }
171 
RunAsync()172 bool ExecuteCodeFunction::RunAsync() {
173   EXTENSION_FUNCTION_VALIDATE(Init());
174 
175   if (!details_->code.get() && !details_->file.get()) {
176     error_ = keys::kNoCodeOrFileToExecuteError;
177     return false;
178   }
179   if (details_->code.get() && details_->file.get()) {
180     error_ = keys::kMoreThanOneValuesError;
181     return false;
182   }
183 
184   if (!CanExecuteScriptOnPage())
185     return false;
186 
187   if (details_->code.get())
188     return Execute(*details_->code);
189 
190   if (!details_->file.get())
191     return false;
192   resource_ = GetExtension()->GetResource(*details_->file);
193 
194   if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
195     error_ = keys::kNoCodeOrFileToExecuteError;
196     return false;
197   }
198 
199   int resource_id;
200   if (ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()->
201       IsComponentExtensionResource(
202           resource_.extension_root(), resource_.relative_path(),
203           &resource_id)) {
204     const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
205     DidLoadFile(true, rb.GetRawDataResource(resource_id).as_string());
206   } else {
207     scoped_refptr<FileReader> file_reader(new FileReader(
208         resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this)));
209     file_reader->Start();
210   }
211 
212   return true;
213 }
214 
OnExecuteCodeFinished(const std::string & error,int32 on_page_id,const GURL & on_url,const base::ListValue & result)215 void ExecuteCodeFunction::OnExecuteCodeFinished(
216     const std::string& error,
217     int32 on_page_id,
218     const GURL& on_url,
219     const base::ListValue& result) {
220   if (!error.empty())
221     SetError(error);
222 
223   SendResponse(error.empty());
224 }
225 
226 }  // namespace extensions
227