blob: 44de6bf7f33e9487779ab2405ea3924b088954d3 [file] [log] [blame]
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/execute_code_in_tab_function.h"
#include "base/callback.h"
#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extension_tabs_module_constants.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/file_reader.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_utils.h"
namespace keys = extension_tabs_module_constants;
bool ExecuteCodeInTabFunction::RunImpl() {
DictionaryValue* script_info;
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &script_info));
size_t number_of_value = script_info->size();
if (number_of_value == 0) {
error_ = keys::kNoCodeOrFileToExecuteError;
return false;
} else {
bool has_code = script_info->HasKey(keys::kCodeKey);
bool has_file = script_info->HasKey(keys::kFileKey);
if (has_code && has_file) {
error_ = keys::kMoreThanOneValuesError;
return false;
} else if (!has_code && !has_file) {
error_ = keys::kNoCodeOrFileToExecuteError;
return false;
}
}
execute_tab_id_ = -1;
Browser* browser = NULL;
TabContents* contents = NULL;
// If |tab_id| is specified, look for it. Otherwise default to selected tab
// in the current window.
Value* tab_value = NULL;
EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
if (tab_value->IsType(Value::TYPE_NULL)) {
browser = GetCurrentBrowser();
if (!browser) {
error_ = keys::kNoCurrentWindowError;
return false;
}
if (!ExtensionTabUtil::GetDefaultTab(browser, &contents, &execute_tab_id_))
return false;
} else {
EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&execute_tab_id_));
if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(),
include_incognito(),
&browser, NULL, &contents, NULL)) {
return false;
}
}
DCHECK(browser);
DCHECK(contents);
// NOTE: This can give the wrong answer due to race conditions, but it is OK,
// we check again in the renderer.
if (!profile()->GetExtensionsService()->CanExecuteScriptOnHost(
GetExtension(), contents->GetURL(), &error_))
return false;
if (script_info->HasKey(keys::kAllFramesKey)) {
if (!script_info->GetBoolean(keys::kAllFramesKey, &all_frames_))
return false;
}
std::string code_string;
if (script_info->HasKey(keys::kCodeKey)) {
if (!script_info->GetString(keys::kCodeKey, &code_string))
return false;
}
if (!code_string.empty()) {
if (!Execute(code_string))
return false;
return true;
}
std::string relative_path;
if (script_info->HasKey(keys::kFileKey)) {
if (!script_info->GetString(keys::kFileKey, &relative_path))
return false;
resource_ = GetExtension()->GetResource(relative_path);
}
if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
error_ = keys::kNoCodeOrFileToExecuteError;
return false;
}
scoped_refptr<FileReader> file_reader(new FileReader(
resource_, NewCallback(this, &ExecuteCodeInTabFunction::DidLoadFile)));
file_reader->Start();
AddRef(); // Keep us alive until DidLoadFile is called.
return true;
}
void ExecuteCodeInTabFunction::DidLoadFile(bool success,
const std::string& data) {
if (success) {
Execute(data);
} else {
#if defined(OS_POSIX)
error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
resource_.relative_path().value());
#elif defined(OS_WIN)
error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
WideToUTF8(resource_.relative_path().value()));
#endif // OS_WIN
SendResponse(false);
}
Release(); // Balance the AddRef taken in RunImpl
}
bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) {
TabContents* contents = NULL;
Browser* browser = NULL;
bool success = ExtensionTabUtil::GetTabById(
execute_tab_id_, profile(), include_incognito(), &browser, NULL,
&contents, NULL) && contents && browser;
if (!success) {
SendResponse(false);
return false;
}
Extension* extension = GetExtension();
if (!extension) {
SendResponse(false);
return false;
}
bool is_js_code = true;
std::string function_name = name();
if (function_name == TabsInsertCSSFunction::function_name()) {
is_js_code = false;
} else if (function_name != TabsExecuteScriptFunction::function_name()) {
DCHECK(false);
}
if (!contents->ExecuteCode(request_id(), extension->id(),
extension->host_permissions(), is_js_code,
code_string, all_frames_)) {
SendResponse(false);
return false;
}
registrar_.Add(this, NotificationType::TAB_CODE_EXECUTED,
NotificationService::AllSources());
AddRef(); // balanced in Observe()
return true;
}
void ExecuteCodeInTabFunction::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
std::pair<int, bool>* result_details =
Details<std::pair<int, bool> >(details).ptr();
if (result_details->first == request_id()) {
SendResponse(result_details->second);
Release(); // balanced in Execute()
}
}