1// Copyright (c) 2012 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/script_executor.h" 6 7#include "base/callback.h" 8#include "base/logging.h" 9#include "base/pickle.h" 10#include "chrome/common/extensions/extension_messages.h" 11#include "content/public/browser/render_view_host.h" 12#include "content/public/browser/web_contents.h" 13#include "content/public/browser/web_contents_observer.h" 14#include "ipc/ipc_message.h" 15#include "ipc/ipc_message_macros.h" 16 17namespace base { 18class ListValue; 19} // namespace base 20 21namespace extensions { 22 23namespace { 24 25const char* kRendererDestroyed = "The tab was closed."; 26 27// A handler for a single injection request. On creation this will send the 28// injection request to the renderer, and it will be destroyed after either the 29// corresponding response comes from the renderer, or the renderer is destroyed. 30class Handler : public content::WebContentsObserver { 31 public: 32 Handler(ObserverList<TabHelper::ScriptExecutionObserver>* script_observers, 33 content::WebContents* web_contents, 34 const ExtensionMsg_ExecuteCode_Params& params, 35 const ScriptExecutor::ExecuteScriptCallback& callback) 36 : content::WebContentsObserver(web_contents), 37 script_observers_(AsWeakPtr(script_observers)), 38 extension_id_(params.extension_id), 39 request_id_(params.request_id), 40 callback_(callback) { 41 content::RenderViewHost* rvh = web_contents->GetRenderViewHost(); 42 rvh->Send(new ExtensionMsg_ExecuteCode(rvh->GetRoutingID(), params)); 43 } 44 45 virtual ~Handler() {} 46 47 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 48 // Unpack by hand to check the request_id, since there may be multiple 49 // requests in flight but only one is for this. 50 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID) 51 return false; 52 53 int message_request_id; 54 PickleIterator iter(message); 55 CHECK(message.ReadInt(&iter, &message_request_id)); 56 57 if (message_request_id != request_id_) 58 return false; 59 60 IPC_BEGIN_MESSAGE_MAP(Handler, message) 61 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished, 62 OnExecuteCodeFinished) 63 IPC_END_MESSAGE_MAP() 64 return true; 65 } 66 67 virtual void WebContentsDestroyed(content::WebContents* tab) OVERRIDE { 68 base::ListValue val; 69 callback_.Run(kRendererDestroyed, -1, GURL(std::string()), val); 70 delete this; 71 } 72 73 private: 74 void OnExecuteCodeFinished(int request_id, 75 const std::string& error, 76 int32 on_page_id, 77 const GURL& on_url, 78 const base::ListValue& script_result) { 79 if (script_observers_.get() && error.empty()) { 80 TabHelper::ScriptExecutionObserver::ExecutingScriptsMap id_map; 81 id_map[extension_id_] = std::set<std::string>(); 82 FOR_EACH_OBSERVER(TabHelper::ScriptExecutionObserver, *script_observers_, 83 OnScriptsExecuted(web_contents(), 84 id_map, 85 on_page_id, 86 on_url)); 87 } 88 89 callback_.Run(error, on_page_id, on_url, script_result); 90 delete this; 91 } 92 93 base::WeakPtr<ObserverList<TabHelper::ScriptExecutionObserver> > 94 script_observers_; 95 std::string extension_id_; 96 int request_id_; 97 ScriptExecutor::ExecuteScriptCallback callback_; 98}; 99 100} // namespace 101 102ScriptExecutor::ScriptExecutor( 103 content::WebContents* web_contents, 104 ObserverList<TabHelper::ScriptExecutionObserver>* script_observers) 105 : next_request_id_(0), 106 web_contents_(web_contents), 107 script_observers_(script_observers) {} 108 109ScriptExecutor::~ScriptExecutor() {} 110 111void ScriptExecutor::ExecuteScript( 112 const std::string& extension_id, 113 ScriptExecutor::ScriptType script_type, 114 const std::string& code, 115 ScriptExecutor::FrameScope frame_scope, 116 UserScript::RunLocation run_at, 117 ScriptExecutor::WorldType world_type, 118 bool is_web_view, 119 const ExecuteScriptCallback& callback) { 120 ExtensionMsg_ExecuteCode_Params params; 121 params.request_id = next_request_id_++; 122 params.extension_id = extension_id; 123 params.is_javascript = (script_type == JAVASCRIPT); 124 params.code = code; 125 params.all_frames = (frame_scope == ALL_FRAMES); 126 params.run_at = static_cast<int>(run_at); 127 params.in_main_world = (world_type == MAIN_WORLD); 128 params.is_web_view = is_web_view; 129 130 // Handler handles IPCs and deletes itself on completion. 131 new Handler(script_observers_, web_contents_, params, callback); 132} 133 134} // namespace extensions 135