Home | History | Annotate | Download | only in extensions
      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 
     17 namespace base {
     18 class ListValue;
     19 }  // namespace base
     20 
     21 namespace extensions {
     22 
     23 namespace {
     24 
     25 const 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.
     30 class 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 
    102 ScriptExecutor::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 
    109 ScriptExecutor::~ScriptExecutor() {}
    110 
    111 void 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