| // Copyright (c) 2012 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/script_executor.h" |
| |
| #include "base/callback.h" |
| #include "base/logging.h" |
| #include "base/pickle.h" |
| #include "chrome/common/extensions/extension_messages.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "ipc/ipc_message.h" |
| #include "ipc/ipc_message_macros.h" |
| |
| namespace base { |
| class ListValue; |
| } // namespace base |
| |
| namespace extensions { |
| |
| namespace { |
| |
| const char* kRendererDestroyed = "The tab was closed."; |
| |
| // A handler for a single injection request. On creation this will send the |
| // injection request to the renderer, and it will be destroyed after either the |
| // corresponding response comes from the renderer, or the renderer is destroyed. |
| class Handler : public content::WebContentsObserver { |
| public: |
| Handler(ObserverList<TabHelper::ScriptExecutionObserver>* script_observers, |
| content::WebContents* web_contents, |
| const ExtensionMsg_ExecuteCode_Params& params, |
| const ScriptExecutor::ExecuteScriptCallback& callback) |
| : content::WebContentsObserver(web_contents), |
| script_observers_(AsWeakPtr(script_observers)), |
| extension_id_(params.extension_id), |
| request_id_(params.request_id), |
| callback_(callback) { |
| content::RenderViewHost* rvh = web_contents->GetRenderViewHost(); |
| rvh->Send(new ExtensionMsg_ExecuteCode(rvh->GetRoutingID(), params)); |
| } |
| |
| virtual ~Handler() {} |
| |
| virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
| // Unpack by hand to check the request_id, since there may be multiple |
| // requests in flight but only one is for this. |
| if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID) |
| return false; |
| |
| int message_request_id; |
| PickleIterator iter(message); |
| CHECK(message.ReadInt(&iter, &message_request_id)); |
| |
| if (message_request_id != request_id_) |
| return false; |
| |
| IPC_BEGIN_MESSAGE_MAP(Handler, message) |
| IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished, |
| OnExecuteCodeFinished) |
| IPC_END_MESSAGE_MAP() |
| return true; |
| } |
| |
| virtual void WebContentsDestroyed(content::WebContents* tab) OVERRIDE { |
| base::ListValue val; |
| callback_.Run(kRendererDestroyed, -1, GURL(std::string()), val); |
| delete this; |
| } |
| |
| private: |
| void OnExecuteCodeFinished(int request_id, |
| const std::string& error, |
| int32 on_page_id, |
| const GURL& on_url, |
| const base::ListValue& script_result) { |
| if (script_observers_.get() && error.empty()) { |
| TabHelper::ScriptExecutionObserver::ExecutingScriptsMap id_map; |
| id_map[extension_id_] = std::set<std::string>(); |
| FOR_EACH_OBSERVER(TabHelper::ScriptExecutionObserver, *script_observers_, |
| OnScriptsExecuted(web_contents(), |
| id_map, |
| on_page_id, |
| on_url)); |
| } |
| |
| callback_.Run(error, on_page_id, on_url, script_result); |
| delete this; |
| } |
| |
| base::WeakPtr<ObserverList<TabHelper::ScriptExecutionObserver> > |
| script_observers_; |
| std::string extension_id_; |
| int request_id_; |
| ScriptExecutor::ExecuteScriptCallback callback_; |
| }; |
| |
| } // namespace |
| |
| ScriptExecutor::ScriptExecutor( |
| content::WebContents* web_contents, |
| ObserverList<TabHelper::ScriptExecutionObserver>* script_observers) |
| : next_request_id_(0), |
| web_contents_(web_contents), |
| script_observers_(script_observers) {} |
| |
| ScriptExecutor::~ScriptExecutor() {} |
| |
| void ScriptExecutor::ExecuteScript( |
| const std::string& extension_id, |
| ScriptExecutor::ScriptType script_type, |
| const std::string& code, |
| ScriptExecutor::FrameScope frame_scope, |
| UserScript::RunLocation run_at, |
| ScriptExecutor::WorldType world_type, |
| ScriptExecutor::ProcessType process_type, |
| const GURL& file_url, |
| ScriptExecutor::ResultType result_type, |
| const ExecuteScriptCallback& callback) { |
| ExtensionMsg_ExecuteCode_Params params; |
| params.request_id = next_request_id_++; |
| params.extension_id = extension_id; |
| params.is_javascript = (script_type == JAVASCRIPT); |
| params.code = code; |
| params.all_frames = (frame_scope == ALL_FRAMES); |
| params.run_at = static_cast<int>(run_at); |
| params.in_main_world = (world_type == MAIN_WORLD); |
| params.is_web_view = (process_type == WEB_VIEW_PROCESS); |
| params.file_url = file_url; |
| params.wants_result = (result_type == JSON_SERIALIZED_RESULT); |
| |
| // Handler handles IPCs and deletes itself on completion. |
| new Handler(script_observers_, web_contents_, params, callback); |
| } |
| |
| } // namespace extensions |