blob: cb0e8a14689fa2c0fb9c9516819419bd94add69f [file] [log] [blame]
[email protected]3c220782014-05-20 01:59:461// Copyright 2014 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 "extensions/renderer/script_injection.h"
6
[email protected]ac2f89372014-06-23 21:44:257#include <map>
dchenge59eca1602015-12-18 17:48:008#include <utility>
[email protected]3c220782014-05-20 01:59:469
10#include "base/lazy_instance.h"
avi2d124c02015-12-23 06:36:4211#include "base/macros.h"
jdoerriee067999a2017-04-07 06:39:0012#include "base/memory/ptr_util.h"
asvitkinef5d4ee562016-11-07 18:57:0813#include "base/metrics/histogram_macros.h"
[email protected]c11e6592014-06-27 17:07:3414#include "base/timer/elapsed_timer.h"
15#include "base/values.h"
mek87e0ab52015-02-13 01:18:2616#include "content/public/child/v8_value_converter.h"
rdevlin.cronin3e11c9862015-06-04 19:54:2517#include "content/public/renderer/render_frame.h"
[email protected]f8abc6e42014-06-24 21:14:4318#include "extensions/common/extension_messages.h"
ksakamotocbf167aa2017-03-17 06:45:4819#include "extensions/common/feature_switch.h"
hanxia5c856cf2015-02-13 20:51:5820#include "extensions/common/host_id.h"
[email protected]c11e6592014-06-27 17:07:3421#include "extensions/renderer/dom_activity_logger.h"
rdevlin.croninc318b93d2015-09-14 20:22:2922#include "extensions/renderer/extension_frame_helper.h"
[email protected]ac2f89372014-06-23 21:44:2523#include "extensions/renderer/extensions_renderer_client.h"
kozyatinskiyc8bc9a582015-03-06 09:33:4124#include "extensions/renderer/script_injection_callback.h"
kozyatinskiyc8bc9a582015-03-06 09:33:4125#include "extensions/renderer/scripts_run_info.h"
mek966863c2016-02-04 23:39:0526#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
[email protected]c11e6592014-06-27 17:07:3427#include "third_party/WebKit/public/platform/WebString.h"
28#include "third_party/WebKit/public/web/WebDocument.h"
dcheng2e449172014-09-24 04:30:5629#include "third_party/WebKit/public/web/WebLocalFrame.h"
[email protected]c11e6592014-06-27 17:07:3430#include "third_party/WebKit/public/web/WebScriptSource.h"
[email protected]c11e6592014-06-27 17:07:3431#include "url/gurl.h"
[email protected]3c220782014-05-20 01:59:4632
33namespace extensions {
34
35namespace {
36
hanxia5c856cf2015-02-13 20:51:5837using IsolatedWorldMap = std::map<std::string, int>;
scottmg5e65e3a2017-03-08 08:48:4638base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
[email protected]3c220782014-05-20 01:59:4639 LAZY_INSTANCE_INITIALIZER;
40
avi2d124c02015-12-23 06:36:4241const int64_t kInvalidRequestId = -1;
[email protected]f8abc6e42014-06-24 21:14:4342
43// The id of the next pending injection.
avi2d124c02015-12-23 06:36:4244int64_t g_next_pending_id = 0;
[email protected]f8abc6e42014-06-24 21:14:4345
hanxia5c856cf2015-02-13 20:51:5846// Gets the isolated world ID to use for the given |injection_host|
47// in the given |frame|. If no isolated world has been created for that
48// |injection_host| one will be created and initialized.
49int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host,
50 blink::WebLocalFrame* frame) {
[email protected]ac2f89372014-06-23 21:44:2551 static int g_next_isolated_world_id =
52 ExtensionsRendererClient::Get()->GetLowestIsolatedWorldId();
[email protected]0d8d6972014-06-03 22:41:0253
[email protected]ac2f89372014-06-23 21:44:2554 IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
[email protected]0d8d6972014-06-03 22:41:0255
[email protected]ac2f89372014-06-23 21:44:2556 int id = 0;
hanxia5c856cf2015-02-13 20:51:5857 const std::string& key = injection_host->id().id();
58 IsolatedWorldMap::iterator iter = isolated_worlds.find(key);
[email protected]ac2f89372014-06-23 21:44:2559 if (iter != isolated_worlds.end()) {
60 id = iter->second;
61 } else {
62 id = g_next_isolated_world_id++;
63 // This map will tend to pile up over time, but realistically, you're never
hanxia5c856cf2015-02-13 20:51:5864 // going to have enough injection hosts for it to matter.
65 isolated_worlds[key] = id;
[email protected]0d8d6972014-06-03 22:41:0266 }
67
[email protected]ac2f89372014-06-23 21:44:2568 // We need to set the isolated world origin and CSP even if it's not a new
69 // world since these are stored per frame, and we might not have used this
70 // isolated world in this frame before.
Blink Reformat1c4d759e2017-04-09 16:34:5471 frame->SetIsolatedWorldSecurityOrigin(
72 id, blink::WebSecurityOrigin::Create(injection_host->url()));
73 frame->SetIsolatedWorldContentSecurityPolicy(
74 id,
75 blink::WebString::FromUTF8(injection_host->GetContentSecurityPolicy()));
76 frame->SetIsolatedWorldHumanReadableName(
77 id, blink::WebString::FromUTF8(injection_host->name()));
[email protected]ac2f89372014-06-23 21:44:2578
79 return id;
[email protected]0d8d6972014-06-03 22:41:0280}
81
ksakamotocbf167aa2017-03-17 06:45:4882// This class manages its own lifetime.
83class TimedScriptInjectionCallback : public ScriptInjectionCallback {
84 public:
85 explicit TimedScriptInjectionCallback(
86 base::WeakPtr<ScriptInjection> injection)
87 : ScriptInjectionCallback(
88 base::Bind(&TimedScriptInjectionCallback::OnCompleted,
89 base::Unretained(this))),
90 injection_(injection) {}
91 ~TimedScriptInjectionCallback() override {}
92
93 void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
94 if (injection_) {
ksakamoto4178f502017-04-07 04:40:2195 base::Optional<base::TimeDelta> elapsed;
96 // If the script will never execute (such as if the context is destroyed),
97 // willExecute() will not be called, but OnCompleted() will. Only log a
98 // time for execution if the script, in fact, executed.
99 if (!start_time_.is_null())
100 elapsed = base::TimeTicks::Now() - start_time_;
ksakamotocbf167aa2017-03-17 06:45:48101 injection_->OnJsInjectionCompleted(result, elapsed);
102 }
103 }
104
Blink Reformat1c4d759e2017-04-09 16:34:54105 void WillExecute() override { start_time_ = base::TimeTicks::Now(); }
ksakamotocbf167aa2017-03-17 06:45:48106
107 private:
108 base::WeakPtr<ScriptInjection> injection_;
109 base::TimeTicks start_time_;
110};
111
[email protected]c11e6592014-06-27 17:07:34112} // namespace
113
rdevlin.cronind533be962015-10-02 17:01:18114// Watches for the deletion of a RenderFrame, after which is_valid will return
115// false.
116class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
117 public:
118 FrameWatcher(content::RenderFrame* render_frame,
119 ScriptInjection* injection)
120 : content::RenderFrameObserver(render_frame),
121 injection_(injection) {}
122 ~FrameWatcher() override {}
123
124 private:
125 void FrameDetached() override { injection_->invalidate_render_frame(); }
126 void OnDestruct() override { injection_->invalidate_render_frame(); }
127
128 ScriptInjection* injection_;
129
130 DISALLOW_COPY_AND_ASSIGN(FrameWatcher);
131};
132
[email protected]ac2f89372014-06-23 21:44:25133// static
hanxia5c856cf2015-02-13 20:51:58134std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
135 const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
[email protected]0d8d6972014-06-03 22:41:02136
hanxia5c856cf2015-02-13 20:51:58137 for (const auto& iter : isolated_worlds) {
138 if (iter.second == isolated_world_id)
139 return iter.first;
[email protected]3c220782014-05-20 01:59:46140 }
[email protected]ac2f89372014-06-23 21:44:25141 return std::string();
[email protected]3c220782014-05-20 01:59:46142}
143
[email protected]ac2f89372014-06-23 21:44:25144// static
hanxia5c856cf2015-02-13 20:51:58145void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
146 g_isolated_worlds.Get().erase(host_id);
[email protected]3c220782014-05-20 01:59:46147}
148
dchengf6f80662016-04-20 20:26:04149ScriptInjection::ScriptInjection(
150 std::unique_ptr<ScriptInjector> injector,
151 content::RenderFrame* render_frame,
152 std::unique_ptr<const InjectionHost> injection_host,
rdevlin.cronin6fba7ec2016-06-24 16:15:05153 UserScript::RunLocation run_location,
154 bool log_activity)
dchenge59eca1602015-12-18 17:48:00155 : injector_(std::move(injector)),
rdevlin.cronin3e11c9862015-06-04 19:54:25156 render_frame_(render_frame),
dchenge59eca1602015-12-18 17:48:00157 injection_host_(std::move(injection_host)),
[email protected]f8abc6e42014-06-24 21:14:43158 run_location_(run_location),
[email protected]d2056002014-07-03 06:18:06159 request_id_(kInvalidRequestId),
kozyatinskiyc8bc9a582015-03-06 09:33:41160 complete_(false),
rdevlin.cronin3e11c9862015-06-04 19:54:25161 did_inject_js_(false),
rdevlin.cronin6fba7ec2016-06-24 16:15:05162 log_activity_(log_activity),
rdevlin.cronind533be962015-10-02 17:01:18163 frame_watcher_(new FrameWatcher(render_frame, this)),
rdevlin.cronin3e11c9862015-06-04 19:54:25164 weak_ptr_factory_(this) {
hanxi9b841662015-03-04 14:36:41165 CHECK(injection_host_.get());
[email protected]f8abc6e42014-06-24 21:14:43166}
167
168ScriptInjection::~ScriptInjection() {
169 if (!complete_)
rdevlin.cronind533be962015-10-02 17:01:18170 NotifyWillNotInject(ScriptInjector::WONT_INJECT);
[email protected]f8abc6e42014-06-24 21:14:43171}
172
kozyatinskiyc8bc9a582015-03-06 09:33:41173ScriptInjection::InjectionResult ScriptInjection::TryToInject(
174 UserScript::RunLocation current_location,
175 ScriptsRunInfo* scripts_run_info,
rdevlin.cronin4bb32d72015-06-02 21:55:01176 const CompletionCallback& async_completion_callback) {
[email protected]f8abc6e42014-06-24 21:14:43177 if (current_location < run_location_)
kozyatinskiyc8bc9a582015-03-06 09:33:41178 return INJECTION_WAITING; // Wait for the right location.
[email protected]f8abc6e42014-06-24 21:14:43179
kozyatinskiyc8bc9a582015-03-06 09:33:41180 if (request_id_ != kInvalidRequestId) {
181 // We're waiting for permission right now, try again later.
182 return INJECTION_WAITING;
183 }
[email protected]f8abc6e42014-06-24 21:14:43184
hanxi9b841662015-03-04 14:36:41185 if (!injection_host_) {
[email protected]c11e6592014-06-27 17:07:34186 NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
kozyatinskiyc8bc9a582015-03-06 09:33:41187 return INJECTION_FINISHED; // We're done.
[email protected]f8abc6e42014-06-24 21:14:43188 }
189
rdevlin.cronin3e11c9862015-06-04 19:54:25190 blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
hanxi9b841662015-03-04 14:36:41191 switch (injector_->CanExecuteOnFrame(
rdevlin.croninc318b93d2015-09-14 20:22:29192 injection_host_.get(), web_frame,
193 ExtensionFrameHelper::Get(render_frame_)->tab_id())) {
[email protected]23a85362014-07-07 23:26:19194 case PermissionsData::ACCESS_DENIED:
[email protected]c11e6592014-06-27 17:07:34195 NotifyWillNotInject(ScriptInjector::NOT_ALLOWED);
kozyatinskiyc8bc9a582015-03-06 09:33:41196 return INJECTION_FINISHED; // We're done.
[email protected]23a85362014-07-07 23:26:19197 case PermissionsData::ACCESS_WITHHELD:
rdevlin.croninb03d1572015-10-02 02:23:52198 RequestPermissionFromBrowser();
kozyatinskiyc8bc9a582015-03-06 09:33:41199 return INJECTION_WAITING; // Wait around for permission.
[email protected]23a85362014-07-07 23:26:19200 case PermissionsData::ACCESS_ALLOWED:
kozyatinskiyc8bc9a582015-03-06 09:33:41201 InjectionResult result = Inject(scripts_run_info);
202 // If the injection is blocked, we need to set the manager so we can
203 // notify it upon completion.
204 if (result == INJECTION_BLOCKED)
rdevlin.cronin4bb32d72015-06-02 21:55:01205 async_completion_callback_ = async_completion_callback;
kozyatinskiyc8bc9a582015-03-06 09:33:41206 return result;
[email protected]f8abc6e42014-06-24 21:14:43207 }
208
rdevlin.cronin958e9f82015-02-17 21:57:14209 NOTREACHED();
kozyatinskiyc8bc9a582015-03-06 09:33:41210 return INJECTION_FINISHED;
[email protected]f8abc6e42014-06-24 21:14:43211}
212
kozyatinskiyc8bc9a582015-03-06 09:33:41213ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
214 ScriptsRunInfo* scripts_run_info) {
hanxi9b841662015-03-04 14:36:41215 if (!injection_host_) {
[email protected]c11e6592014-06-27 17:07:34216 NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
kozyatinskiyc8bc9a582015-03-06 09:33:41217 return INJECTION_FINISHED;
[email protected]f8abc6e42014-06-24 21:14:43218 }
219
kozyatinskiyc8bc9a582015-03-06 09:33:41220 return Inject(scripts_run_info);
[email protected]f8abc6e42014-06-24 21:14:43221}
222
hanxi9b841662015-03-04 14:36:41223void ScriptInjection::OnHostRemoved() {
224 injection_host_.reset(nullptr);
225}
226
rdevlin.croninb03d1572015-10-02 02:23:52227void ScriptInjection::RequestPermissionFromBrowser() {
[email protected]23a85362014-07-07 23:26:19228 // If we are just notifying the browser of the injection, then send an
[email protected]f8abc6e42014-06-24 21:14:43229 // invalid request (which is treated like a notification).
rdevlin.croninb03d1572015-10-02 02:23:52230 request_id_ = g_next_pending_id++;
rdevlin.cronin45dca7f2015-06-08 19:47:03231 render_frame_->Send(new ExtensionHostMsg_RequestScriptInjectionPermission(
rdevlin.cronin8d034e52016-02-02 22:46:32232 render_frame_->GetRoutingID(), host_id().id(), injector_->script_type(),
233 run_location_, request_id_));
[email protected]f8abc6e42014-06-24 21:14:43234}
235
[email protected]c11e6592014-06-27 17:07:34236void ScriptInjection::NotifyWillNotInject(
237 ScriptInjector::InjectFailureReason reason) {
[email protected]f8abc6e42014-06-24 21:14:43238 complete_ = true;
rdevlin.cronind533be962015-10-02 17:01:18239 injector_->OnWillNotInject(reason, render_frame_);
[email protected]f8abc6e42014-06-24 21:14:43240}
241
kozyatinskiyc8bc9a582015-03-06 09:33:41242ScriptInjection::InjectionResult ScriptInjection::Inject(
243 ScriptsRunInfo* scripts_run_info) {
hanxi9b841662015-03-04 14:36:41244 DCHECK(injection_host_);
[email protected]c11e6592014-06-27 17:07:34245 DCHECK(scripts_run_info);
246 DCHECK(!complete_);
catmullingsd4faad4f2016-09-08 19:55:30247 bool should_inject_js = injector_->ShouldInjectJs(
248 run_location_, scripts_run_info->executing_scripts[host_id().id()]);
249 bool should_inject_css = injector_->ShouldInjectCss(
250 run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
[email protected]c11e6592014-06-27 17:07:34251
catmullingsd4faad4f2016-09-08 19:55:30252 // This can happen if the extension specified a script to
253 // be run in multiple rules, and the script has already run.
254 // See crbug.com/631247.
255 if (!should_inject_js && !should_inject_css) {
256 return INJECTION_FINISHED;
257 }
[email protected]c11e6592014-06-27 17:07:34258
rdevlin.cronin4bb32d72015-06-02 21:55:01259 if (should_inject_js)
catmullingsd4faad4f2016-09-08 19:55:30260 InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
261 &(scripts_run_info->num_js));
rdevlin.cronin4bb32d72015-06-02 21:55:01262 if (should_inject_css)
catmullingsd4faad4f2016-09-08 19:55:30263 InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
264 &(scripts_run_info->num_css));
[email protected]c11e6592014-06-27 17:07:34265
rdevlin.cronin4bb32d72015-06-02 21:55:01266 complete_ = did_inject_js_ || !should_inject_js;
[email protected]c11e6592014-06-27 17:07:34267
rdevlin.cronind533be962015-10-02 17:01:18268 if (complete_) {
dchenge59eca1602015-12-18 17:48:00269 injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
rdevlin.cronind533be962015-10-02 17:01:18270 render_frame_);
271 } else {
rdevlin.cronin4bb32d72015-06-02 21:55:01272 ++scripts_run_info->num_blocking_js;
rdevlin.cronind533be962015-10-02 17:01:18273 }
rdevlin.cronin4bb32d72015-06-02 21:55:01274
kozyatinskiyc8bc9a582015-03-06 09:33:41275 return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
[email protected]c11e6592014-06-27 17:07:34276}
277
catmullingsd4faad4f2016-09-08 19:55:30278void ScriptInjection::InjectJs(std::set<std::string>* executing_scripts,
279 size_t* num_injected_js_scripts) {
rdevlin.cronin4bb32d72015-06-02 21:55:01280 DCHECK(!did_inject_js_);
rdevlin.cronin3e11c9862015-06-04 19:54:25281 blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
catmullingsd4faad4f2016-09-08 19:55:30282 std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
283 run_location_, executing_scripts, num_injected_js_scripts);
284 DCHECK(!sources.empty());
[email protected]c11e6592014-06-27 17:07:34285 bool in_main_world = injector_->ShouldExecuteInMainWorld();
286 int world_id = in_main_world
287 ? DOMActivityLogger::kMainWorldId
hanxi9b841662015-03-04 14:36:41288 : GetIsolatedWorldIdForInstance(injection_host_.get(),
rdevlin.cronin3e11c9862015-06-04 19:54:25289 web_frame);
kozyatinskiyc8bc9a582015-03-06 09:33:41290 bool is_user_gesture = injector_->IsUserGesture();
291
dchengf6f80662016-04-20 20:26:04292 std::unique_ptr<blink::WebScriptExecutionCallback> callback(
ksakamotocbf167aa2017-03-17 06:45:48293 new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr()));
[email protected]c11e6592014-06-27 17:07:34294
295 base::ElapsedTimer exec_timer;
rdevlin.cronin6fba7ec2016-06-24 16:15:05296 if (injection_host_->id().type() == HostID::EXTENSIONS && log_activity_)
hanxi9b841662015-03-04 14:36:41297 DOMActivityLogger::AttachToWorld(world_id, injection_host_->id().id());
[email protected]c11e6592014-06-27 17:07:34298 if (in_main_world) {
299 // We only inject in the main world for javascript: urls.
300 DCHECK_EQ(1u, sources.size());
301
Blink Reformat1c4d759e2017-04-09 16:34:54302 web_frame->RequestExecuteScriptAndReturnValue(
303 sources.front(), is_user_gesture, callback.release());
kozyatinskiyc8bc9a582015-03-06 09:33:41304 } else {
ksakamotocbf167aa2017-03-17 06:45:48305 blink::WebLocalFrame::ScriptExecutionType option;
306 if (injector_->script_type() == UserScript::CONTENT_SCRIPT &&
307 FeatureSwitch::yield_between_content_script_runs()->IsEnabled()) {
308 switch (run_location_) {
309 case UserScript::DOCUMENT_END:
310 case UserScript::DOCUMENT_IDLE:
Blink Reformat1c4d759e2017-04-09 16:34:54311 option = blink::WebLocalFrame::kAsynchronousBlockingOnload;
ksakamotocbf167aa2017-03-17 06:45:48312 break;
313 default:
Blink Reformat1c4d759e2017-04-09 16:34:54314 option = blink::WebLocalFrame::kSynchronous;
ksakamotocbf167aa2017-03-17 06:45:48315 break;
316 }
317 } else {
Blink Reformat1c4d759e2017-04-09 16:34:54318 option = blink::WebLocalFrame::kSynchronous;
ksakamotocbf167aa2017-03-17 06:45:48319 }
Blink Reformat1c4d759e2017-04-09 16:34:54320 web_frame->RequestExecuteScriptInIsolatedWorld(
ksakamotocbf167aa2017-03-17 06:45:48321 world_id, &sources.front(), sources.size(), is_user_gesture, option,
rdevlin.cronin3e11c9862015-06-04 19:54:25322 callback.release());
[email protected]c11e6592014-06-27 17:07:34323 }
kozyatinskiyc8bc9a582015-03-06 09:33:41324}
[email protected]c11e6592014-06-27 17:07:34325
kozyatinskiyc8bc9a582015-03-06 09:33:41326void ScriptInjection::OnJsInjectionCompleted(
ksakamotocbf167aa2017-03-17 06:45:48327 const std::vector<v8::Local<v8::Value>>& results,
ksakamoto4178f502017-04-07 04:40:21328 base::Optional<base::TimeDelta> elapsed) {
rdevlin.cronin4bb32d72015-06-02 21:55:01329 DCHECK(!did_inject_js_);
kozyatinskiyc8bc9a582015-03-06 09:33:41330
ksakamoto4178f502017-04-07 04:40:21331 if (injection_host_->id().type() == HostID::EXTENSIONS && elapsed) {
332 UMA_HISTOGRAM_TIMES("Extensions.InjectedScriptExecutionTime", *elapsed);
ksakamoto049f8332017-03-24 06:39:07333 switch (run_location_) {
334 case UserScript::DOCUMENT_START:
335 UMA_HISTOGRAM_TIMES(
ksakamoto4178f502017-04-07 04:40:21336 "Extensions.InjectedScriptExecutionTime.DocumentStart", *elapsed);
ksakamoto049f8332017-03-24 06:39:07337 break;
338 case UserScript::DOCUMENT_END:
339 UMA_HISTOGRAM_TIMES(
ksakamoto4178f502017-04-07 04:40:21340 "Extensions.InjectedScriptExecutionTime.DocumentEnd", *elapsed);
ksakamoto049f8332017-03-24 06:39:07341 break;
342 case UserScript::DOCUMENT_IDLE:
343 UMA_HISTOGRAM_TIMES(
ksakamoto4178f502017-04-07 04:40:21344 "Extensions.InjectedScriptExecutionTime.DocumentIdle", *elapsed);
ksakamoto049f8332017-03-24 06:39:07345 break;
346 default:
347 break;
348 }
349 }
ksakamotocbf167aa2017-03-17 06:45:48350
kozyatinskiyc8bc9a582015-03-06 09:33:41351 bool expects_results = injector_->ExpectsResults();
[email protected]c11e6592014-06-27 17:07:34352 if (expects_results) {
rdevlin.cronin0d94256f2016-12-09 15:34:23353 if (!results.empty() && !results[0].IsEmpty()) {
kozyatinskiyefaa59a2015-04-03 17:57:16354 // Right now, we only support returning single results (per frame).
dchengf6f80662016-04-20 20:26:04355 std::unique_ptr<content::V8ValueConverter> v8_converter(
kozyatinskiyefaa59a2015-04-03 17:57:16356 content::V8ValueConverter::create());
357 // It's safe to always use the main world context when converting
358 // here. V8ValueConverterImpl shouldn't actually care about the
359 // context scope, and it switches to v8::Object's creation context
360 // when encountered.
rdevlin.cronin3e11c9862015-06-04 19:54:25361 v8::Local<v8::Context> context =
Blink Reformat1c4d759e2017-04-09 16:34:54362 render_frame_->GetWebFrame()->MainWorldScriptContext();
dcheng0232f572016-05-27 17:47:44363 execution_result_ = v8_converter->FromV8Value(results[0], context);
kozyatinskiyefaa59a2015-04-03 17:57:16364 }
rdevlin.cronin4bb32d72015-06-02 21:55:01365 if (!execution_result_.get())
jdoerriee067999a2017-04-07 06:39:00366 execution_result_ = base::MakeUnique<base::Value>();
kozyatinskiyc8bc9a582015-03-06 09:33:41367 }
rdevlin.cronin4bb32d72015-06-02 21:55:01368 did_inject_js_ = true;
kozyatinskiyc8bc9a582015-03-06 09:33:41369
rdevlin.cronin4bb32d72015-06-02 21:55:01370 // If |async_completion_callback_| is set, it means the script finished
371 // asynchronously, and we should run it.
372 if (!async_completion_callback_.is_null()) {
ksakamotocbf167aa2017-03-17 06:45:48373 complete_ = true;
dchenge59eca1602015-12-18 17:48:00374 injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
rdevlin.cronind533be962015-10-02 17:01:18375 render_frame_);
rdevlin.cronin4bb32d72015-06-02 21:55:01376 // Warning: this object can be destroyed after this line!
377 async_completion_callback_.Run(this);
[email protected]c11e6592014-06-27 17:07:34378 }
379}
380
catmullingsd4faad4f2016-09-08 19:55:30381void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
382 size_t* num_injected_stylesheets) {
383 std::vector<blink::WebString> css_sources = injector_->GetCssSources(
384 run_location_, injected_stylesheets, num_injected_stylesheets);
rdevlin.cronin3e11c9862015-06-04 19:54:25385 blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
lazyboy49cc0b3a2016-08-18 21:55:12386 for (const blink::WebString& css : css_sources)
Blink Reformat1c4d759e2017-04-09 16:34:54387 web_frame->GetDocument().InsertStyleSheet(css);
[email protected]f8abc6e42014-06-24 21:14:43388}
389
[email protected]3c220782014-05-20 01:59:46390} // namespace extensions