1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/renderer/script_injection.h"
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <map>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/lazy_instance.h"
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/metrics/histogram.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/timer/elapsed_timer.h"
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/values.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/renderer/render_view.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/renderer/v8_value_converter.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/extension.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/extension_messages.h"
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/feature_switch.h"
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/manifest_handlers/csp_info.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/renderer/dom_activity_logger.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/renderer/extension_groups.h"
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/renderer/extensions_renderer_client.h"
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "third_party/WebKit/public/platform/WebString.h"
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "third_party/WebKit/public/web/WebDocument.h"
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/WebKit/public/web/WebLocalFrame.h"
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "third_party/WebKit/public/web/WebScriptSource.h"
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "url/gurl.h"
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace extensions {
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace {
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef std::map<std::string, int> IsolatedWorldMap;
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbase::LazyInstance<IsolatedWorldMap> g_isolated_worlds =
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LAZY_INSTANCE_INITIALIZER;
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int64 kInvalidRequestId = -1;
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// The id of the next pending injection.
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint64 g_next_pending_id = 0;
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool ShouldNotifyBrowserOfInjections() {
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return !FeatureSwitch::scripts_require_action()->IsEnabled();
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Append all the child frames of |parent_frame| to |frames_vector|.
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid AppendAllChildFrames(blink::WebFrame* parent_frame,
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          std::vector<blink::WebFrame*>* frames_vector) {
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(parent_frame);
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (blink::WebFrame* child_frame = parent_frame->firstChild(); child_frame;
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       child_frame = child_frame->nextSibling()) {
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    frames_vector->push_back(child_frame);
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    AppendAllChildFrames(child_frame, frames_vector);
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Gets the isolated world ID to use for the given |extension| in the given
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// |frame|. If no isolated world has been created for that extension,
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// one will be created and initialized.
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint GetIsolatedWorldIdForExtension(const Extension* extension,
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   blink::WebLocalFrame* frame) {
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static int g_next_isolated_world_id =
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ExtensionsRendererClient::Get()->GetLowestIsolatedWorldId();
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int id = 0;
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IsolatedWorldMap::iterator iter = isolated_worlds.find(extension->id());
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (iter != isolated_worlds.end()) {
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    id = iter->second;
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    id = g_next_isolated_world_id++;
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // This map will tend to pile up over time, but realistically, you're never
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // going to have enough extensions for it to matter.
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    isolated_worlds[extension->id()] = id;
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // We need to set the isolated world origin and CSP even if it's not a new
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // world since these are stored per frame, and we might not have used this
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // isolated world in this frame before.
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  frame->setIsolatedWorldSecurityOrigin(
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      id, blink::WebSecurityOrigin::create(extension->url()));
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  frame->setIsolatedWorldContentSecurityPolicy(
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      id,
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      blink::WebString::fromUTF8(CSPInfo::GetContentSecurityPolicy(extension)));
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  frame->setIsolatedWorldHumanReadableName(
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      id,
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      blink::WebString::fromUTF8(extension->name()));
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return id;
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstd::string ScriptInjection::GetExtensionIdForIsolatedWorld(
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int isolated_world_id) {
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (IsolatedWorldMap::iterator iter = isolated_worlds.begin();
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != isolated_worlds.end();
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++iter) {
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (iter->second == isolated_world_id)
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return iter->first;
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return std::string();
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjection::RemoveIsolatedWorld(const std::string& extension_id) {
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  g_isolated_worlds.Get().erase(extension_id);
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ScriptInjection::ScriptInjection(
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ScriptInjector> injector,
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    blink::WebLocalFrame* web_frame,
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::string& extension_id,
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    UserScript::RunLocation run_location,
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int tab_id)
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : injector_(injector.Pass()),
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      web_frame_(web_frame),
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension_id_(extension_id),
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      run_location_(run_location),
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      tab_id_(tab_id),
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      request_id_(kInvalidRequestId),
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      complete_(false) {
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ScriptInjection::~ScriptInjection() {
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!complete_)
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    injector_->OnWillNotInject(ScriptInjector::WONT_INJECT);
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool ScriptInjection::TryToInject(UserScript::RunLocation current_location,
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  const Extension* extension,
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  ScriptsRunInfo* scripts_run_info) {
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (current_location < run_location_)
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;  // Wait for the right location.
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (request_id_ != kInvalidRequestId)
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;  // We're waiting for permission right now, try again later.
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!extension) {
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return true;  // We're done.
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (injector_->CanExecuteOnFrame(
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension, web_frame_, tab_id_, web_frame_->top()->document().url())) {
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case PermissionsData::ACCESS_DENIED:
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      NotifyWillNotInject(ScriptInjector::NOT_ALLOWED);
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return true;  // We're done.
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case PermissionsData::ACCESS_WITHHELD:
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      RequestPermission();
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;  // Wait around for permission.
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case PermissionsData::ACCESS_ALLOWED:
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      Inject(extension, scripts_run_info);
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return true;  // We're done!
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Some compilers don't realize that we always return from the switch() above.
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Make them happy.
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return false;
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool ScriptInjection::OnPermissionGranted(const Extension* extension,
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          ScriptsRunInfo* scripts_run_info) {
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!extension) {
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  Inject(extension, scripts_run_info);
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return true;
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjection::RequestPermission() {
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  content::RenderView* render_view =
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      content::RenderView::FromWebView(web_frame()->top()->view());
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If we are just notifying the browser of the injection, then send an
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // invalid request (which is treated like a notification).
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  request_id_ = ShouldNotifyBrowserOfInjections() ? kInvalidRequestId
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                  : g_next_pending_id++;
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  render_view->Send(new ExtensionHostMsg_RequestScriptInjectionPermission(
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      render_view->GetRoutingID(),
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension_id_,
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      injector_->script_type(),
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      request_id_));
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjection::NotifyWillNotInject(
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ScriptInjector::InjectFailureReason reason) {
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  complete_ = true;
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  injector_->OnWillNotInject(reason);
19746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjection::Inject(const Extension* extension,
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             ScriptsRunInfo* scripts_run_info) {
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(extension);
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(scripts_run_info);
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!complete_);
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (ShouldNotifyBrowserOfInjections())
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RequestPermission();
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<blink::WebFrame*> frame_vector;
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  frame_vector.push_back(web_frame_);
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (injector_->ShouldExecuteInChildFrames())
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    AppendAllChildFrames(web_frame_, &frame_vector);
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<blink::WebScopedUserGesture> gesture;
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (injector_->IsUserGesture())
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gesture.reset(new blink::WebScopedUserGesture());
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool inject_js = injector_->ShouldInjectJs(run_location_);
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool inject_css = injector_->ShouldInjectCss(run_location_);
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(inject_js || inject_css);
22046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<base::ListValue> execution_results(new base::ListValue());
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GURL top_url = web_frame_->top()->document().url();
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (std::vector<blink::WebFrame*>::iterator iter = frame_vector.begin();
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != frame_vector.end();
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++iter) {
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(dcheng): Unfortunately, the code as written won't work in an OOPI
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // world. This is just a temporary hack to make things compile.
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    blink::WebLocalFrame* frame = (*iter)->toWebLocalFrame();
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // We recheck access here in the renderer for extra safety against races
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // with navigation, but different frames can have different URLs, and the
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // extension might only have access to a subset of them.
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // For child frames, we just skip ones the extension doesn't have access
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // to and carry on.
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Note: we don't consider ACCESS_WITHHELD because there is nowhere to
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // surface a request for a child frame.
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // TODO(rdevlin.cronin): We should ask for permission somehow.
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (injector_->CanExecuteOnFrame(extension, frame, tab_id_, top_url) ==
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        PermissionsData::ACCESS_DENIED) {
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      DCHECK(frame->parent());
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      continue;
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (inject_js)
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      InjectJs(extension, frame, execution_results.get());
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (inject_css)
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      InjectCss(frame);
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  complete_ = true;
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  injector_->OnInjectionComplete(execution_results.Pass(),
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                 scripts_run_info,
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                 run_location_);
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
255116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ScriptInjection::InjectJs(const Extension* extension,
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               blink::WebLocalFrame* frame,
257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                               base::ListValue* execution_results) {
258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<blink::WebScriptSource> sources =
259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      injector_->GetJsSources(run_location_);
260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool in_main_world = injector_->ShouldExecuteInMainWorld();
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int world_id = in_main_world
262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     ? DOMActivityLogger::kMainWorldId
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     : GetIsolatedWorldIdForExtension(extension, frame);
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool expects_results = injector_->ExpectsResults();
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::ElapsedTimer exec_timer;
267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DOMActivityLogger::AttachToWorld(world_id, extension->id());
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  v8::HandleScope scope(v8::Isolate::GetCurrent());
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  v8::Local<v8::Value> script_value;
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (in_main_world) {
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // We only inject in the main world for javascript: urls.
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK_EQ(1u, sources.size());
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const blink::WebScriptSource& source = sources.front();
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (expects_results)
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      script_value = frame->executeScriptAndReturnValue(source);
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    else
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      frame->executeScript(source);
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {  // in isolated world
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<blink::WebVector<v8::Local<v8::Value> > > results;
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (expects_results)
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      results.reset(new blink::WebVector<v8::Local<v8::Value> >());
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    frame->executeScriptInIsolatedWorld(world_id,
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        &sources.front(),
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        sources.size(),
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        EXTENSION_GROUP_CONTENT_SCRIPTS,
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        results.get());
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (expects_results && !results->isEmpty())
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      script_value = (*results)[0];
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("Extensions.InjectScriptTime", exec_timer.Elapsed());
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (expects_results) {
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Right now, we only support returning single results (per frame).
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<content::V8ValueConverter> v8_converter(
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        content::V8ValueConverter::create());
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // It's safe to always use the main world context when converting
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // here. V8ValueConverterImpl shouldn't actually care about the
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // context scope, and it switches to v8::Object's creation context
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // when encountered.
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    v8::Local<v8::Context> context = frame->mainWorldScriptContext();
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<base::Value> result(
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        v8_converter->FromV8Value(script_value, context));
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Always append an execution result (i.e. no result == null result)
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // so that |execution_results| lines up with the frames.
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    execution_results->Append(result.get() ? result.release()
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                           : base::Value::CreateNullValue());
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ScriptInjection::InjectCss(blink::WebLocalFrame* frame) {
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<std::string> css_sources =
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      injector_->GetCssSources(run_location_);
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (std::vector<std::string>::const_iterator iter = css_sources.begin();
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != css_sources.end();
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       ++iter) {
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    frame->document().insertStyleSheet(blink::WebString::fromUTF8(*iter));
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace extensions
323