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/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"
     18 
     19 namespace extensions {
     20 
     21 namespace keys = tabs_constants;
     22 using api::tabs::InjectDetails;
     23 
     24 ExecuteCodeFunction::ExecuteCodeFunction() {
     25 }
     26 
     27 ExecuteCodeFunction::~ExecuteCodeFunction() {
     28 }
     29 
     30 void ExecuteCodeFunction::DidLoadFile(bool success,
     31                                       const std::string& data) {
     32 
     33   if (!success || !details_->file) {
     34     DidLoadAndLocalizeFile(success, data);
     35     return;
     36   }
     37 
     38   ScriptExecutor::ScriptType script_type =
     39       ShouldInsertCSS() ? ScriptExecutor::CSS : ScriptExecutor::JAVASCRIPT;
     40 
     41   std::string extension_id;
     42   base::FilePath extension_path;
     43   std::string extension_default_locale;
     44   const Extension* extension = GetExtension();
     45   if (extension) {
     46     extension_id = extension->id();
     47     extension_path = extension->path();
     48     extension_default_locale = LocaleInfo::GetDefaultLocale(extension);
     49   }
     50 
     51   content::BrowserThread::PostTask(
     52       content::BrowserThread::FILE, FROM_HERE,
     53       base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS, this,
     54                   script_type,
     55                   data,
     56                   extension_id,
     57                   extension_path,
     58                   extension_default_locale));
     59 }
     60 
     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) {
     67 
     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));
     76 
     77     // We need to do message replacement on the data, so it has to be mutable.
     78     std::string error;
     79     MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages,
     80                                                          &localized_data,
     81                                                          &error);
     82   }
     83 
     84   file_url_ = net::FilePathToFileURL(resource_.GetFilePath());
     85 
     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));
     93 }
     94 
     95 void ExecuteCodeFunction::DidLoadAndLocalizeFile(bool success,
     96                                                  const std::string& data) {
     97   if (success) {
     98     if (!Execute(data))
     99       SendResponse(false);
    100   } else {
    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());
    105     SendResponse(false);
    106   }
    107 }
    108 
    109 bool ExecuteCodeFunction::Execute(const std::string& code_string) {
    110   ScriptExecutor* executor = GetScriptExecutor();
    111   if (!executor)
    112     return false;
    113 
    114   const Extension* extension = GetExtension();
    115   if (!extension)
    116     return false;
    117 
    118   ScriptExecutor::ScriptType script_type = ScriptExecutor::JAVASCRIPT;
    119   if (ShouldInsertCSS())
    120     script_type = ScriptExecutor::CSS;
    121 
    122   ScriptExecutor::FrameScope frame_scope =
    123       details_->all_frames.get() && *details_->all_frames ?
    124           ScriptExecutor::ALL_FRAMES :
    125           ScriptExecutor::TOP_FRAME;
    126 
    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;
    133       break;
    134     case InjectDetails::RUN_AT_DOCUMENT_START:
    135       run_at = UserScript::DOCUMENT_START;
    136       break;
    137     case InjectDetails::RUN_AT_DOCUMENT_END:
    138       run_at = UserScript::DOCUMENT_END;
    139       break;
    140   }
    141   CHECK_NE(UserScript::UNDEFINED, run_at);
    142 
    143   executor->ExecuteScript(
    144       extension->id(),
    145       script_type,
    146       code_string,
    147       frame_scope,
    148       run_at,
    149       ScriptExecutor::ISOLATED_WORLD,
    150       IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS
    151                   : ScriptExecutor::DEFAULT_PROCESS,
    152       file_url_,
    153       has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT
    154                      : ScriptExecutor::NO_RESULT,
    155       base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished, this));
    156   return true;
    157 }
    158 
    159 bool ExecuteCodeFunction::HasPermission() {
    160   return true;
    161 }
    162 
    163 bool ExecuteCodeFunction::RunImpl() {
    164   EXTENSION_FUNCTION_VALIDATE(Init());
    165 
    166   if (!details_->code.get() && !details_->file.get()) {
    167     error_ = keys::kNoCodeOrFileToExecuteError;
    168     return false;
    169   }
    170   if (details_->code.get() && details_->file.get()) {
    171     error_ = keys::kMoreThanOneValuesError;
    172     return false;
    173   }
    174 
    175   if (!CanExecuteScriptOnPage())
    176     return false;
    177 
    178   if (details_->code.get())
    179     return Execute(*details_->code);
    180 
    181   if (!details_->file.get())
    182     return false;
    183   resource_ = GetExtension()->GetResource(*details_->file);
    184 
    185   if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
    186     error_ = keys::kNoCodeOrFileToExecuteError;
    187     return false;
    188   }
    189 
    190   int resource_id;
    191   if (ImageLoader::IsComponentExtensionResource(
    192           resource_.extension_root(), resource_.relative_path(),
    193           &resource_id)) {
    194     const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    195     DidLoadFile(true, rb.GetRawDataResource(resource_id).as_string());
    196   } else {
    197     scoped_refptr<FileReader> file_reader(new FileReader(
    198         resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this)));
    199     file_reader->Start();
    200   }
    201 
    202   return true;
    203 }
    204 
    205 void ExecuteCodeFunction::OnExecuteCodeFinished(
    206     const std::string& error,
    207     int32 on_page_id,
    208     const GURL& on_url,
    209     const base::ListValue& result) {
    210   if (!error.empty())
    211     SetError(error);
    212 
    213   SendResponse(error.empty());
    214 }
    215 
    216 }  // namespace extensions
    217