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 "chrome/common/extensions/extension_file_util.h"
     11 #include "chrome/common/extensions/extension_messages.h"
     12 #include "chrome/common/extensions/message_bundle.h"
     13 #include "extensions/browser/file_reader.h"
     14 #include "extensions/common/error_utils.h"
     15 
     16 namespace extensions {
     17 
     18 namespace keys = tabs_constants;
     19 using api::tabs::InjectDetails;
     20 
     21 ExecuteCodeFunction::ExecuteCodeFunction() {
     22 }
     23 
     24 ExecuteCodeFunction::~ExecuteCodeFunction() {
     25 }
     26 
     27 void ExecuteCodeFunction::DidLoadFile(bool success,
     28                                       const std::string& data) {
     29   const Extension* extension = GetExtension();
     30 
     31   // Check if the file is CSS and needs localization.
     32   if (success &&
     33       ShouldInsertCSS() &&
     34       extension != NULL &&
     35       data.find(MessageBundle::kMessageBegin) != std::string::npos) {
     36     content::BrowserThread::PostTask(
     37         content::BrowserThread::FILE, FROM_HERE,
     38         base::Bind(&ExecuteCodeFunction::LocalizeCSS, this,
     39                    data,
     40                    extension->id(),
     41                    extension->path(),
     42                    LocaleInfo::GetDefaultLocale(extension)));
     43   } else {
     44     DidLoadAndLocalizeFile(success, data);
     45   }
     46 }
     47 
     48 void ExecuteCodeFunction::LocalizeCSS(
     49     const std::string& data,
     50     const std::string& extension_id,
     51     const base::FilePath& extension_path,
     52     const std::string& extension_default_locale) {
     53   scoped_ptr<SubstitutionMap> localization_messages(
     54       extension_file_util::LoadMessageBundleSubstitutionMap(
     55           extension_path, extension_id, extension_default_locale));
     56 
     57   // We need to do message replacement on the data, so it has to be mutable.
     58   std::string css_data = data;
     59   std::string error;
     60   MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages,
     61                                                        &css_data,
     62                                                        &error);
     63 
     64   // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter
     65   // is always true, because if loading had failed, we wouldn't have had
     66   // anything to localize.
     67   content::BrowserThread::PostTask(
     68       content::BrowserThread::UI, FROM_HERE,
     69       base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this,
     70                  true, css_data));
     71 }
     72 
     73 void ExecuteCodeFunction::DidLoadAndLocalizeFile(bool success,
     74                                                  const std::string& data) {
     75   if (success) {
     76     if (!Execute(data))
     77       SendResponse(false);
     78   } else {
     79     // TODO(viettrungluu): bug: there's no particular reason the path should be
     80     // UTF-8, in which case this may fail.
     81     error_ = ErrorUtils::FormatErrorMessage(keys::kLoadFileError,
     82         resource_.relative_path().AsUTF8Unsafe());
     83     SendResponse(false);
     84   }
     85 }
     86 
     87 bool ExecuteCodeFunction::Execute(const std::string& code_string) {
     88   ScriptExecutor* executor = GetScriptExecutor();
     89   if (!executor)
     90     return false;
     91 
     92   const Extension* extension = GetExtension();
     93   if (!extension)
     94     return false;
     95 
     96   ScriptExecutor::ScriptType script_type = ScriptExecutor::JAVASCRIPT;
     97   if (ShouldInsertCSS())
     98     script_type = ScriptExecutor::CSS;
     99 
    100   ScriptExecutor::FrameScope frame_scope =
    101       details_->all_frames.get() && *details_->all_frames ?
    102           ScriptExecutor::ALL_FRAMES :
    103           ScriptExecutor::TOP_FRAME;
    104 
    105   UserScript::RunLocation run_at =
    106       UserScript::UNDEFINED;
    107   switch (details_->run_at) {
    108     case InjectDetails::RUN_AT_NONE:
    109     case InjectDetails::RUN_AT_DOCUMENT_IDLE:
    110       run_at = UserScript::DOCUMENT_IDLE;
    111       break;
    112     case InjectDetails::RUN_AT_DOCUMENT_START:
    113       run_at = UserScript::DOCUMENT_START;
    114       break;
    115     case InjectDetails::RUN_AT_DOCUMENT_END:
    116       run_at = UserScript::DOCUMENT_END;
    117       break;
    118   }
    119   CHECK_NE(UserScript::UNDEFINED, run_at);
    120 
    121   executor->ExecuteScript(
    122       extension->id(),
    123       script_type,
    124       code_string,
    125       frame_scope,
    126       run_at,
    127       ScriptExecutor::ISOLATED_WORLD,
    128       IsWebView(),
    129       base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished, this));
    130   return true;
    131 }
    132 
    133 bool ExecuteCodeFunction::HasPermission() {
    134   return true;
    135 }
    136 
    137 bool ExecuteCodeFunction::RunImpl() {
    138   EXTENSION_FUNCTION_VALIDATE(Init());
    139 
    140   if (!details_->code.get() && !details_->file.get()) {
    141     error_ = keys::kNoCodeOrFileToExecuteError;
    142     return false;
    143   }
    144   if (details_->code.get() && details_->file.get()) {
    145     error_ = keys::kMoreThanOneValuesError;
    146     return false;
    147   }
    148 
    149   if (!CanExecuteScriptOnPage())
    150     return false;
    151 
    152   if (details_->code.get())
    153     return Execute(*details_->code);
    154 
    155   if (!details_->file.get())
    156     return false;
    157   resource_ = GetExtension()->GetResource(*details_->file);
    158 
    159   if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
    160     error_ = keys::kNoCodeOrFileToExecuteError;
    161     return false;
    162   }
    163 
    164   scoped_refptr<FileReader> file_reader(new FileReader(
    165       resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this)));
    166   file_reader->Start();
    167 
    168   return true;
    169 }
    170 
    171 void ExecuteCodeFunction::OnExecuteCodeFinished(
    172     const std::string& error,
    173     int32 on_page_id,
    174     const GURL& on_url,
    175     const base::ListValue& result) {
    176   if (!error.empty())
    177     SetError(error);
    178 
    179   SendResponse(error.empty());
    180 }
    181 
    182 }  // namespace extensions
    183