| // Copyright (c) 2013 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/api/execute_code_function.h" |
| |
| #include "chrome/browser/extensions/api/tabs/tabs_constants.h" |
| #include "chrome/browser/extensions/image_loader.h" |
| #include "chrome/browser/extensions/script_executor.h" |
| #include "chrome/common/extensions/api/i18n/default_locale_handler.h" |
| #include "chrome/common/extensions/extension_file_util.h" |
| #include "chrome/common/extensions/extension_messages.h" |
| #include "chrome/common/extensions/message_bundle.h" |
| #include "extensions/browser/file_reader.h" |
| #include "extensions/common/error_utils.h" |
| #include "net/base/net_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| |
| namespace extensions { |
| |
| namespace keys = tabs_constants; |
| using api::tabs::InjectDetails; |
| |
| ExecuteCodeFunction::ExecuteCodeFunction() { |
| } |
| |
| ExecuteCodeFunction::~ExecuteCodeFunction() { |
| } |
| |
| void ExecuteCodeFunction::DidLoadFile(bool success, |
| const std::string& data) { |
| |
| if (!success || !details_->file) { |
| DidLoadAndLocalizeFile(success, data); |
| return; |
| } |
| |
| ScriptExecutor::ScriptType script_type = |
| ShouldInsertCSS() ? ScriptExecutor::CSS : ScriptExecutor::JAVASCRIPT; |
| |
| std::string extension_id; |
| base::FilePath extension_path; |
| std::string extension_default_locale; |
| const Extension* extension = GetExtension(); |
| if (extension) { |
| extension_id = extension->id(); |
| extension_path = extension->path(); |
| extension_default_locale = LocaleInfo::GetDefaultLocale(extension); |
| } |
| |
| content::BrowserThread::PostTask( |
| content::BrowserThread::FILE, FROM_HERE, |
| base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS, this, |
| script_type, |
| data, |
| extension_id, |
| extension_path, |
| extension_default_locale)); |
| } |
| |
| void ExecuteCodeFunction::GetFileURLAndLocalizeCSS( |
| ScriptExecutor::ScriptType script_type, |
| const std::string& data, |
| const std::string& extension_id, |
| const base::FilePath& extension_path, |
| const std::string& extension_default_locale) { |
| |
| std::string localized_data = data; |
| // Check if the file is CSS and needs localization. |
| if ((script_type == ScriptExecutor::CSS) && |
| !extension_id.empty() && |
| (data.find(MessageBundle::kMessageBegin) != std::string::npos)) { |
| scoped_ptr<SubstitutionMap> localization_messages( |
| extension_file_util::LoadMessageBundleSubstitutionMap( |
| extension_path, extension_id, extension_default_locale)); |
| |
| // We need to do message replacement on the data, so it has to be mutable. |
| std::string error; |
| MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages, |
| &localized_data, |
| &error); |
| } |
| |
| file_url_ = net::FilePathToFileURL(resource_.GetFilePath()); |
| |
| // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter |
| // is always true, because if loading had failed, we wouldn't have had |
| // anything to localize. |
| content::BrowserThread::PostTask( |
| content::BrowserThread::UI, FROM_HERE, |
| base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this, |
| true, localized_data)); |
| } |
| |
| void ExecuteCodeFunction::DidLoadAndLocalizeFile(bool success, |
| const std::string& data) { |
| if (success) { |
| if (!Execute(data)) |
| SendResponse(false); |
| } else { |
| // TODO(viettrungluu): bug: there's no particular reason the path should be |
| // UTF-8, in which case this may fail. |
| error_ = ErrorUtils::FormatErrorMessage(keys::kLoadFileError, |
| resource_.relative_path().AsUTF8Unsafe()); |
| SendResponse(false); |
| } |
| } |
| |
| bool ExecuteCodeFunction::Execute(const std::string& code_string) { |
| ScriptExecutor* executor = GetScriptExecutor(); |
| if (!executor) |
| return false; |
| |
| const Extension* extension = GetExtension(); |
| if (!extension) |
| return false; |
| |
| ScriptExecutor::ScriptType script_type = ScriptExecutor::JAVASCRIPT; |
| if (ShouldInsertCSS()) |
| script_type = ScriptExecutor::CSS; |
| |
| ScriptExecutor::FrameScope frame_scope = |
| details_->all_frames.get() && *details_->all_frames ? |
| ScriptExecutor::ALL_FRAMES : |
| ScriptExecutor::TOP_FRAME; |
| |
| UserScript::RunLocation run_at = |
| UserScript::UNDEFINED; |
| switch (details_->run_at) { |
| case InjectDetails::RUN_AT_NONE: |
| case InjectDetails::RUN_AT_DOCUMENT_IDLE: |
| run_at = UserScript::DOCUMENT_IDLE; |
| break; |
| case InjectDetails::RUN_AT_DOCUMENT_START: |
| run_at = UserScript::DOCUMENT_START; |
| break; |
| case InjectDetails::RUN_AT_DOCUMENT_END: |
| run_at = UserScript::DOCUMENT_END; |
| break; |
| } |
| CHECK_NE(UserScript::UNDEFINED, run_at); |
| |
| executor->ExecuteScript( |
| extension->id(), |
| script_type, |
| code_string, |
| frame_scope, |
| run_at, |
| ScriptExecutor::ISOLATED_WORLD, |
| IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS |
| : ScriptExecutor::DEFAULT_PROCESS, |
| file_url_, |
| has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT |
| : ScriptExecutor::NO_RESULT, |
| base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished, this)); |
| return true; |
| } |
| |
| bool ExecuteCodeFunction::HasPermission() { |
| return true; |
| } |
| |
| bool ExecuteCodeFunction::RunImpl() { |
| EXTENSION_FUNCTION_VALIDATE(Init()); |
| |
| if (!details_->code.get() && !details_->file.get()) { |
| error_ = keys::kNoCodeOrFileToExecuteError; |
| return false; |
| } |
| if (details_->code.get() && details_->file.get()) { |
| error_ = keys::kMoreThanOneValuesError; |
| return false; |
| } |
| |
| if (!CanExecuteScriptOnPage()) |
| return false; |
| |
| if (details_->code.get()) |
| return Execute(*details_->code); |
| |
| if (!details_->file.get()) |
| return false; |
| resource_ = GetExtension()->GetResource(*details_->file); |
| |
| if (resource_.extension_root().empty() || resource_.relative_path().empty()) { |
| error_ = keys::kNoCodeOrFileToExecuteError; |
| return false; |
| } |
| |
| int resource_id; |
| if (ImageLoader::IsComponentExtensionResource( |
| resource_.extension_root(), resource_.relative_path(), |
| &resource_id)) { |
| const ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| DidLoadFile(true, rb.GetRawDataResource(resource_id).as_string()); |
| } else { |
| scoped_refptr<FileReader> file_reader(new FileReader( |
| resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this))); |
| file_reader->Start(); |
| } |
| |
| return true; |
| } |
| |
| void ExecuteCodeFunction::OnExecuteCodeFinished( |
| const std::string& error, |
| int32 on_page_id, |
| const GURL& on_url, |
| const base::ListValue& result) { |
| if (!error.empty()) |
| SetError(error); |
| |
| SendResponse(error.empty()); |
| } |
| |
| } // namespace extensions |