Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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/execute_code_in_tab_function.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/string_util.h"
      9 #include "base/utf_string_conversions.h"
     10 #include "chrome/browser/extensions/extension_service.h"
     11 #include "chrome/browser/extensions/extension_tabs_module.h"
     12 #include "chrome/browser/extensions/extension_tabs_module_constants.h"
     13 #include "chrome/browser/extensions/file_reader.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/browser.h"
     16 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     17 #include "chrome/common/extensions/extension.h"
     18 #include "chrome/common/extensions/extension_constants.h"
     19 #include "chrome/common/extensions/extension_error_utils.h"
     20 #include "chrome/common/extensions/extension_messages.h"
     21 #include "content/browser/renderer_host/render_view_host.h"
     22 #include "content/browser/tab_contents/tab_contents.h"
     23 #include "content/browser/renderer_host/render_view_host.h"
     24 #include "content/common/notification_service.h"
     25 
     26 namespace keys = extension_tabs_module_constants;
     27 
     28 ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
     29     : ALLOW_THIS_IN_INITIALIZER_LIST(registrar_(this)),
     30       execute_tab_id_(-1),
     31       all_frames_(false) {
     32 }
     33 
     34 ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {
     35 }
     36 
     37 bool ExecuteCodeInTabFunction::RunImpl() {
     38   DictionaryValue* script_info;
     39   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &script_info));
     40   size_t number_of_value = script_info->size();
     41   if (number_of_value == 0) {
     42     error_ = keys::kNoCodeOrFileToExecuteError;
     43     return false;
     44   } else {
     45     bool has_code = script_info->HasKey(keys::kCodeKey);
     46     bool has_file = script_info->HasKey(keys::kFileKey);
     47     if (has_code && has_file) {
     48       error_ = keys::kMoreThanOneValuesError;
     49       return false;
     50     } else if (!has_code && !has_file) {
     51       error_ = keys::kNoCodeOrFileToExecuteError;
     52       return false;
     53     }
     54   }
     55 
     56   execute_tab_id_ = -1;
     57   Browser* browser = NULL;
     58   TabContentsWrapper* contents = NULL;
     59 
     60   // If |tab_id| is specified, look for it. Otherwise default to selected tab
     61   // in the current window.
     62   Value* tab_value = NULL;
     63   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
     64   if (tab_value->IsType(Value::TYPE_NULL)) {
     65     browser = GetCurrentBrowser();
     66     if (!browser) {
     67       error_ = keys::kNoCurrentWindowError;
     68       return false;
     69     }
     70     if (!ExtensionTabUtil::GetDefaultTab(browser, &contents, &execute_tab_id_))
     71       return false;
     72   } else {
     73     EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&execute_tab_id_));
     74     if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(),
     75                                       include_incognito(),
     76                                       &browser, NULL, &contents, NULL)) {
     77       return false;
     78     }
     79   }
     80 
     81   // NOTE: This can give the wrong answer due to race conditions, but it is OK,
     82   // we check again in the renderer.
     83   CHECK(browser);
     84   CHECK(contents);
     85   if (!GetExtension()->CanExecuteScriptOnPage(
     86           contents->tab_contents()->GetURL(), NULL, &error_)) {
     87     return false;
     88   }
     89 
     90   if (script_info->HasKey(keys::kAllFramesKey)) {
     91     if (!script_info->GetBoolean(keys::kAllFramesKey, &all_frames_))
     92       return false;
     93   }
     94 
     95   std::string code_string;
     96   if (script_info->HasKey(keys::kCodeKey)) {
     97     if (!script_info->GetString(keys::kCodeKey, &code_string))
     98       return false;
     99   }
    100 
    101   if (!code_string.empty()) {
    102     if (!Execute(code_string))
    103       return false;
    104     return true;
    105   }
    106 
    107   std::string relative_path;
    108   if (script_info->HasKey(keys::kFileKey)) {
    109     if (!script_info->GetString(keys::kFileKey, &relative_path))
    110       return false;
    111     resource_ = GetExtension()->GetResource(relative_path);
    112   }
    113   if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
    114     error_ = keys::kNoCodeOrFileToExecuteError;
    115     return false;
    116   }
    117 
    118   scoped_refptr<FileReader> file_reader(new FileReader(
    119       resource_, NewCallback(this, &ExecuteCodeInTabFunction::DidLoadFile)));
    120   file_reader->Start();
    121   AddRef();  // Keep us alive until DidLoadFile is called.
    122 
    123   return true;
    124 }
    125 
    126 void ExecuteCodeInTabFunction::DidLoadFile(bool success,
    127                                            const std::string& data) {
    128   if (success) {
    129     Execute(data);
    130   } else {
    131 #if defined(OS_POSIX)
    132     // TODO(viettrungluu): bug: there's no particular reason the path should be
    133     // UTF-8, in which case this may fail.
    134     error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
    135         resource_.relative_path().value());
    136 #elif defined(OS_WIN)
    137     error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
    138         WideToUTF8(resource_.relative_path().value()));
    139 #endif  // OS_WIN
    140     SendResponse(false);
    141   }
    142   Release();  // Balance the AddRef taken in RunImpl
    143 }
    144 
    145 bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) {
    146   TabContentsWrapper* contents = NULL;
    147   Browser* browser = NULL;
    148 
    149   bool success = ExtensionTabUtil::GetTabById(
    150       execute_tab_id_, profile(), include_incognito(), &browser, NULL,
    151       &contents, NULL) && contents && browser;
    152 
    153   if (!success) {
    154     SendResponse(false);
    155     return false;
    156   }
    157 
    158   const Extension* extension = GetExtension();
    159   if (!extension) {
    160     SendResponse(false);
    161     return false;
    162   }
    163 
    164   bool is_js_code = true;
    165   std::string function_name = name();
    166   if (function_name == TabsInsertCSSFunction::function_name()) {
    167     is_js_code = false;
    168   } else if (function_name != TabsExecuteScriptFunction::function_name()) {
    169     DCHECK(false);
    170   }
    171 
    172   ExtensionMsg_ExecuteCode_Params params;
    173   params.request_id = request_id();
    174   params.extension_id = extension->id();
    175   params.is_javascript = is_js_code;
    176   params.code = code_string;
    177   params.all_frames = all_frames_;
    178   params.in_main_world = false;
    179   contents->render_view_host()->Send(new ExtensionMsg_ExecuteCode(
    180       contents->render_view_host()->routing_id(), params));
    181 
    182   registrar_.Observe(contents->tab_contents());
    183   AddRef();  // balanced in OnExecuteCodeFinished()
    184   return true;
    185 }
    186 
    187 bool ExecuteCodeInTabFunction::OnMessageReceived(const IPC::Message& message) {
    188   if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
    189     return false;
    190 
    191   int message_request_id;
    192   void* iter = NULL;
    193   if (!message.ReadInt(&iter, &message_request_id)) {
    194     NOTREACHED() << "malformed extension message";
    195     return true;
    196   }
    197 
    198   if (message_request_id != request_id())
    199     return false;
    200 
    201   IPC_BEGIN_MESSAGE_MAP(ExecuteCodeInTabFunction, message)
    202     IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished,
    203                         OnExecuteCodeFinished)
    204   IPC_END_MESSAGE_MAP()
    205   return true;
    206 }
    207 
    208 void ExecuteCodeInTabFunction::OnExecuteCodeFinished(int request_id,
    209                                                      bool success,
    210                                                      const std::string& error) {
    211   if (!error.empty()) {
    212     CHECK(!success);
    213     error_ = error;
    214   }
    215 
    216   SendResponse(success);
    217 
    218   registrar_.Observe(NULL);
    219   Release();  // balanced in Execute()
    220 }
    221