1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file.
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/renderer/script_injection_manager.h"
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/bind.h"
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/memory/weak_ptr.h"
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/values.h"
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/renderer/render_view.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/renderer/render_view_observer.h"
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/extension.h"
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/extension_messages.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/extension_set.h"
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/renderer/extension_helper.h"
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/renderer/programmatic_script_injector.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/renderer/script_injection.h"
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/renderer/scripts_run_info.h"
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ipc/ipc_message_macros.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/WebKit/public/web/WebDocument.h"
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "third_party/WebKit/public/web/WebFrame.h"
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "third_party/WebKit/public/web/WebLocalFrame.h"
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "third_party/WebKit/public/web/WebView.h"
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "url/gurl.h"
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace extensions {
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// The length of time to wait after the DOM is complete to try and run user
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// scripts.
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kScriptIdleTimeoutInMs = 200;
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass ScriptInjectionManager::RVOHelper : public content::RenderViewObserver {
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch public:
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  RVOHelper(content::RenderView* render_view, ScriptInjectionManager* manager);
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual ~RVOHelper();
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch private:
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // RenderViewObserver implementation.
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE;
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) OVERRIDE;
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void DidFinishLoad(blink::WebLocalFrame* frame) OVERRIDE;
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void DidStartProvisionalLoad(blink::WebLocalFrame* frame) OVERRIDE;
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void FrameDetached(blink::WebFrame* frame) OVERRIDE;
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void OnDestruct() OVERRIDE;
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void OnExecuteCode(const ExtensionMsg_ExecuteCode_Params& params);
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void OnExecuteDeclarativeScript(int tab_id,
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                          const ExtensionId& extension_id,
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                          int script_id,
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                          const GURL& url);
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void OnPermitScriptInjection(int64 request_id);
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Tells the ScriptInjectionManager to run tasks associated with
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // document_idle.
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  void RunIdle(blink::WebFrame* frame);
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Indicate that the given |frame| is no longer valid because it is starting
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // a new load or closing.
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void InvalidateFrame(blink::WebFrame* frame);
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The owning ScriptInjectionManager.
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ScriptInjectionManager* manager_;
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The set of frames that we are about to notify for DOCUMENT_IDLE. We keep
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // a set of those that are valid, so we don't notify that an invalid frame
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // became idle.
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::set<blink::WebFrame*> pending_idle_frames_;
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::WeakPtrFactory<RVOHelper> weak_factory_;
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch};
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
77116680a4aac90f2aa7413d9095a592090648e557Ben MurdochScriptInjectionManager::RVOHelper::RVOHelper(
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::RenderView* render_view,
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ScriptInjectionManager* manager)
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : content::RenderViewObserver(render_view),
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      manager_(manager),
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      weak_factory_(this) {
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
85116680a4aac90f2aa7413d9095a592090648e557Ben MurdochScriptInjectionManager::RVOHelper::~RVOHelper() {
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool ScriptInjectionManager::RVOHelper::OnMessageReceived(
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const IPC::Message& message) {
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool handled = true;
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IPC_BEGIN_MESSAGE_MAP(ScriptInjectionManager::RVOHelper, message)
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode)
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    IPC_MESSAGE_HANDLER(ExtensionMsg_PermitScriptInjection,
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        OnPermitScriptInjection)
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteDeclarativeScript,
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        OnExecuteDeclarativeScript)
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    IPC_MESSAGE_UNHANDLED(handled = false)
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IPC_END_MESSAGE_MAP()
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return handled;
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::DidCreateDocumentElement(
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    blink::WebLocalFrame* frame) {
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  manager_->InjectScripts(frame, UserScript::DOCUMENT_START);
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::DidFinishDocumentLoad(
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    blink::WebLocalFrame* frame) {
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  manager_->InjectScripts(frame, UserScript::DOCUMENT_END);
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pending_idle_frames_.insert(frame);
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We try to run idle in two places: here and DidFinishLoad.
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // DidFinishDocumentLoad() corresponds to completing the document's load,
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // whereas DidFinishLoad corresponds to completing the document and all
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // subresources' load. We don't want to hold up script injection for a
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // particularly slow subresource, so we set a delayed task from here - but if
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // we finish everything before that point (i.e., DidFinishLoad() is
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // triggered), then there's no reason to keep waiting.
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::MessageLoop::current()->PostDelayedTask(
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&ScriptInjectionManager::RVOHelper::RunIdle,
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 weak_factory_.GetWeakPtr(),
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 frame),
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::TimeDelta::FromMilliseconds(kScriptIdleTimeoutInMs));
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::DidFinishLoad(
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    blink::WebLocalFrame* frame) {
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Ensure that we don't block any UI progress by running scripts.
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We *don't* add the frame to |pending_idle_frames_| here because
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // DidFinishDocumentLoad should strictly come before DidFinishLoad, so the
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // first posted task to RunIdle() pops it out of the set. This ensures we
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // don't try to run idle twice.
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::MessageLoop::current()->PostTask(
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&ScriptInjectionManager::RVOHelper::RunIdle,
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 weak_factory_.GetWeakPtr(),
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 frame));
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::DidStartProvisionalLoad(
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    blink::WebLocalFrame* frame) {
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We're starting a new load - invalidate.
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  InvalidateFrame(frame);
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::FrameDetached(blink::WebFrame* frame) {
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The frame is closing - invalidate.
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  InvalidateFrame(frame);
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::OnDestruct() {
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  manager_->RemoveObserver(this);
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::OnExecuteCode(
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ExtensionMsg_ExecuteCode_Params& params) {
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  manager_->HandleExecuteCode(params, render_view());
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ScriptInjectionManager::RVOHelper::OnExecuteDeclarativeScript(
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int tab_id,
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const ExtensionId& extension_id,
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int script_id,
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const GURL& url) {
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  blink::WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(main_frame);
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(markdittmer): This would be cleaner if we compared page_ids instead.
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Begin script injeciton workflow only if the current URL is identical to
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the one that matched declarative conditions in the browser.
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (main_frame->top()->document().url() == url) {
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    manager_->HandleExecuteDeclarativeScript(main_frame,
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             tab_id,
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             extension_id,
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             script_id,
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             url);
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::OnPermitScriptInjection(
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int64 request_id) {
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  manager_->HandlePermitScriptInjection(request_id);
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RVOHelper::RunIdle(blink::WebFrame* frame) {
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Only notify the manager if the frame hasn't either been removed or already
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // had idle run since the task to RunIdle() was posted.
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (pending_idle_frames_.count(frame) > 0) {
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    manager_->InjectScripts(frame, UserScript::DOCUMENT_IDLE);
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    pending_idle_frames_.erase(frame);
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ScriptInjectionManager::RVOHelper::InvalidateFrame(
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    blink::WebFrame* frame) {
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pending_idle_frames_.erase(frame);
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  manager_->InvalidateForFrame(frame);
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
200116680a4aac90f2aa7413d9095a592090648e557Ben MurdochScriptInjectionManager::ScriptInjectionManager(
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ExtensionSet* extensions,
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    UserScriptSetManager* user_script_set_manager)
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : extensions_(extensions),
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      user_script_set_manager_(user_script_set_manager),
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      user_script_set_manager_observer_(this) {
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  user_script_set_manager_observer_.Add(user_script_set_manager_);
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
209116680a4aac90f2aa7413d9095a592090648e557Ben MurdochScriptInjectionManager::~ScriptInjectionManager() {
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::OnRenderViewCreated(
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::RenderView* render_view) {
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  rvo_helpers_.push_back(new RVOHelper(render_view, this));
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::OnUserScriptsUpdated(
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::set<std::string>& changed_extensions,
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::vector<UserScript*>& scripts) {
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (ScopedVector<ScriptInjection>::iterator iter =
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch           pending_injections_.begin();
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != pending_injections_.end();) {
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (changed_extensions.count((*iter)->extension_id()) > 0)
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      iter = pending_injections_.erase(iter);
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    else
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ++iter;
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::RemoveObserver(RVOHelper* helper) {
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (ScopedVector<RVOHelper>::iterator iter = rvo_helpers_.begin();
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != rvo_helpers_.end();
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++iter) {
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (*iter == helper) {
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      rvo_helpers_.erase(iter);
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::InvalidateForFrame(blink::WebFrame* frame) {
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (ScopedVector<ScriptInjection>::iterator iter =
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch           pending_injections_.begin();
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != pending_injections_.end();) {
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if ((*iter)->web_frame() == frame)
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      iter = pending_injections_.erase(iter);
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    else
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ++iter;
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  frame_statuses_.erase(frame);
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::InjectScripts(
255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    blink::WebFrame* frame, UserScript::RunLocation run_location) {
256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  FrameStatusMap::iterator iter = frame_statuses_.find(frame);
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We also don't execute if we detect that the run location is somehow out of
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // order. This can happen if:
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // - The first run location reported for the frame isn't DOCUMENT_START, or
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // - The run location reported doesn't immediately follow the previous
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  //   reported run location.
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We don't want to run because extensions may have requirements that scripts
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // running in an earlier run location have run by the time a later script
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // runs. Better to just not run.
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if ((iter == frame_statuses_.end() &&
2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           run_location != UserScript::DOCUMENT_START) ||
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      (iter != frame_statuses_.end() && run_location - iter->second > 1)) {
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // We also invalidate the frame, because the run order of pending injections
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // may also be bad.
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    InvalidateForFrame(frame);
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (iter != frame_statuses_.end() && iter->second > run_location) {
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Certain run location signals (like DidCreateDocumentElement) can happen
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // multiple times. Ignore the subsequent signals.
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Otherwise, all is right in the world, and we can get on with the
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // injections!
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  frame_statuses_[frame] = run_location;
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Inject any scripts that were waiting for the right run location.
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ScriptsRunInfo scripts_run_info;
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (ScopedVector<ScriptInjection>::iterator iter =
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch           pending_injections_.begin();
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != pending_injections_.end();) {
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if ((*iter)->web_frame() == frame &&
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        (*iter)->TryToInject(run_location,
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             extensions_->GetByID((*iter)->extension_id()),
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             &scripts_run_info)) {
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      iter = pending_injections_.erase(iter);
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ++iter;
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Try to inject any user scripts that should run for this location. If they
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // don't complete their injection (for example, waiting for a permission
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // response) then they will be added to |pending_injections_|.
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ScopedVector<ScriptInjection> user_script_injections;
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView(
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        frame->top()->view()))->tab_id();
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  user_script_set_manager_->GetAllInjections(
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &user_script_injections, frame, tab_id, run_location);
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (ScopedVector<ScriptInjection>::iterator iter =
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch           user_script_injections.begin();
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != user_script_injections.end();) {
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ScriptInjection> injection(*iter);
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    iter = user_script_injections.weak_erase(iter);
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!injection->TryToInject(run_location,
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                extensions_->GetByID(injection->extension_id()),
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                &scripts_run_info)) {
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      pending_injections_.push_back(injection.release());
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scripts_run_info.LogRun(frame, run_location);
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::HandleExecuteCode(
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ExtensionMsg_ExecuteCode_Params& params,
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::RenderView* render_view) {
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(dcheng): Not sure how this can happen today. In an OOPI world, it
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // would indicate a logic error--the browser must direct this request to the
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // right renderer process to begin with.
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  blink::WebLocalFrame* main_frame =
3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      render_view->GetWebView()->mainFrame()->toWebLocalFrame();
329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!main_frame) {
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    render_view->Send(
331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(),
332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                 params.request_id,
333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                 "No main frame",
334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                 GURL(std::string()),
335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                 base::ListValue()));
336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<ScriptInjection> injection(new ScriptInjection(
340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      scoped_ptr<ScriptInjector>(
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          new ProgrammaticScriptInjector(params, main_frame)),
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      main_frame,
343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      params.extension_id,
344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      static_cast<UserScript::RunLocation>(params.run_at),
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ExtensionHelper::Get(render_view)->tab_id()));
346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ScriptsRunInfo scripts_run_info;
348116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame);
349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!injection->TryToInject(
350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second,
351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          extensions_->GetByID(injection->extension_id()),
352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          &scripts_run_info)) {
353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    pending_injections_.push_back(injection.release());
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ScriptInjectionManager::HandleExecuteDeclarativeScript(
3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    blink::WebFrame* web_frame,
3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int tab_id,
3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const ExtensionId& extension_id,
3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int script_id,
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const GURL& url) {
3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const Extension* extension = extensions_->GetByID(extension_id);
3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(dcheng): This function signature should really be a WebLocalFrame,
3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // rather than trying to coerce it here.
3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<ScriptInjection> injection =
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      user_script_set_manager_->GetInjectionForDeclarativeScript(
3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          script_id,
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          web_frame->toWebLocalFrame(),
3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          tab_id,
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          url,
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          extension);
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (injection.get()) {
3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ScriptsRunInfo scripts_run_info;
3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(markdittmer): Use return value of TryToInject for error handling.
3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    injection->TryToInject(UserScript::BROWSER_DRIVEN,
3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           extension,
3781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           &scripts_run_info);
3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scripts_run_info.LogRun(web_frame, UserScript::BROWSER_DRIVEN);
3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
383116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) {
384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ScopedVector<ScriptInjection>::iterator iter =
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      pending_injections_.begin();
386116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (; iter != pending_injections_.end(); ++iter) {
387116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if ((*iter)->request_id() == request_id)
388116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
389116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
390116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (iter == pending_injections_.end())
391116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
392116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
393116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // At this point, because the request is present in pending_injections_, we
394116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // know that this is the same page that issued the request (otherwise,
395116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // RVOHelper's DidStartProvisionalLoad callback would have caused it to be
396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // cleared out).
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<ScriptInjection> injection(*iter);
399116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  pending_injections_.weak_erase(iter);
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ScriptsRunInfo scripts_run_info;
402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (injection->OnPermissionGranted(extensions_->GetByID(
403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                         injection->extension_id()),
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     &scripts_run_info)) {
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scripts_run_info.LogRun(injection->web_frame(), UserScript::RUN_DEFERRED);
406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace extensions
410