Home | History | Annotate | Download | only in api
      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 
     25 ExecuteCodeFunction::ExecuteCodeFunction() {
     26 }
     27 
     28 ExecuteCodeFunction::~ExecuteCodeFunction() {
     29 }
     30 
     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 
     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 
     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 
    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 
    168 bool ExecuteCodeFunction::HasPermission() {
    169   return true;
    170 }
    171 
    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 
    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