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