blob: bb7023bbe249e904eae9e160ba20f36c09e4c03c [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
Devlin Cronin4cd6bc12017-12-05 23:46:4910#include "base/feature_list.h"
[email protected]3c220782014-05-20 01:59:4611#include "base/lazy_instance.h"
avi2d124c02015-12-23 06:36:4212#include "base/macros.h"
jdoerriee067999a2017-04-07 06:39:0013#include "base/memory/ptr_util.h"
asvitkinef5d4ee562016-11-07 18:57:0814#include "base/metrics/histogram_macros.h"
[email protected]c11e6592014-06-27 17:07:3415#include "base/timer/elapsed_timer.h"
16#include "base/values.h"
rdevlin.cronin3e11c9862015-06-04 19:54:2517#include "content/public/renderer/render_frame.h"
John Abd-El-Malek312a30bb2017-10-23 19:51:5218#include "content/public/renderer/v8_value_converter.h"
Devlin Cronin4cd6bc12017-12-05 23:46:4919#include "extensions/common/extension_features.h"
[email protected]f8abc6e42014-06-24 21:14:4320#include "extensions/common/extension_messages.h"
hanxia5c856cf2015-02-13 20:51:5821#include "extensions/common/host_id.h"
Kunihiko Sakamoto7d386bf2017-07-31 03:19:5322#include "extensions/renderer/async_scripts_run_info.h"
[email protected]c11e6592014-06-27 17:07:3423#include "extensions/renderer/dom_activity_logger.h"
rdevlin.croninc318b93d2015-09-14 20:22:2924#include "extensions/renderer/extension_frame_helper.h"
[email protected]ac2f89372014-06-23 21:44:2525#include "extensions/renderer/extensions_renderer_client.h"
kozyatinskiyc8bc9a582015-03-06 09:33:4126#include "extensions/renderer/script_injection_callback.h"
kozyatinskiyc8bc9a582015-03-06 09:33:4127#include "extensions/renderer/scripts_run_info.h"
Blink Reformata30d4232018-04-07 15:31:0628#include "third_party/blink/public/platform/web_security_origin.h"
29#include "third_party/blink/public/platform/web_string.h"
30#include "third_party/blink/public/web/web_document.h"
31#include "third_party/blink/public/web/web_local_frame.h"
32#include "third_party/blink/public/web/web_script_source.h"
[email protected]c11e6592014-06-27 17:07:3433#include "url/gurl.h"
[email protected]3c220782014-05-20 01:59:4634
35namespace extensions {
36
37namespace {
38
hanxia5c856cf2015-02-13 20:51:5839using IsolatedWorldMap = std::map<std::string, int>;
scottmg5e65e3a2017-03-08 08:48:4640base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
[email protected]3c220782014-05-20 01:59:4641 LAZY_INSTANCE_INITIALIZER;
42
avi2d124c02015-12-23 06:36:4243const int64_t kInvalidRequestId = -1;
[email protected]f8abc6e42014-06-24 21:14:4344
45// The id of the next pending injection.
avi2d124c02015-12-23 06:36:4246int64_t g_next_pending_id = 0;
[email protected]f8abc6e42014-06-24 21:14:4347
hanxia5c856cf2015-02-13 20:51:5848// Gets the isolated world ID to use for the given |injection_host|
49// in the given |frame|. If no isolated world has been created for that
50// |injection_host| one will be created and initialized.
51int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host,
52 blink::WebLocalFrame* frame) {
[email protected]ac2f89372014-06-23 21:44:2553 static int g_next_isolated_world_id =
54 ExtensionsRendererClient::Get()->GetLowestIsolatedWorldId();
[email protected]0d8d6972014-06-03 22:41:0255
[email protected]ac2f89372014-06-23 21:44:2556 IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
[email protected]0d8d6972014-06-03 22:41:0257
[email protected]ac2f89372014-06-23 21:44:2558 int id = 0;
hanxia5c856cf2015-02-13 20:51:5859 const std::string& key = injection_host->id().id();
60 IsolatedWorldMap::iterator iter = isolated_worlds.find(key);
[email protected]ac2f89372014-06-23 21:44:2561 if (iter != isolated_worlds.end()) {
62 id = iter->second;
63 } else {
64 id = g_next_isolated_world_id++;
65 // This map will tend to pile up over time, but realistically, you're never
hanxia5c856cf2015-02-13 20:51:5866 // going to have enough injection hosts for it to matter.
67 isolated_worlds[key] = id;
[email protected]0d8d6972014-06-03 22:41:0268 }
69
[email protected]ac2f89372014-06-23 21:44:2570 // We need to set the isolated world origin and CSP even if it's not a new
71 // world since these are stored per frame, and we might not have used this
72 // isolated world in this frame before.
Blink Reformat1c4d759e2017-04-09 16:34:5473 frame->SetIsolatedWorldSecurityOrigin(
74 id, blink::WebSecurityOrigin::Create(injection_host->url()));
75 frame->SetIsolatedWorldContentSecurityPolicy(
76 id,
77 blink::WebString::FromUTF8(injection_host->GetContentSecurityPolicy()));
78 frame->SetIsolatedWorldHumanReadableName(
79 id, blink::WebString::FromUTF8(injection_host->name()));
[email protected]ac2f89372014-06-23 21:44:2580
81 return id;
[email protected]0d8d6972014-06-03 22:41:0282}
83
ksakamotocbf167aa2017-03-17 06:45:4884// This class manages its own lifetime.
85class TimedScriptInjectionCallback : public ScriptInjectionCallback {
86 public:
Kunihiko Sakamoto7d386bf2017-07-31 03:19:5387 TimedScriptInjectionCallback(
88 base::WeakPtr<ScriptInjection> injection,
89 scoped_refptr<AsyncScriptsRunInfo> async_run_info)
ksakamotocbf167aa2017-03-17 06:45:4890 : ScriptInjectionCallback(
91 base::Bind(&TimedScriptInjectionCallback::OnCompleted,
92 base::Unretained(this))),
Kunihiko Sakamoto7d386bf2017-07-31 03:19:5393 injection_(injection),
94 async_run_info_(async_run_info) {}
ksakamotocbf167aa2017-03-17 06:45:4895 ~TimedScriptInjectionCallback() override {}
96
97 void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
98 if (injection_) {
Kunihiko Sakamoto7d386bf2017-07-31 03:19:5399 base::TimeTicks timestamp(base::TimeTicks::Now());
ksakamoto4178f502017-04-07 04:40:21100 base::Optional<base::TimeDelta> elapsed;
101 // If the script will never execute (such as if the context is destroyed),
102 // willExecute() will not be called, but OnCompleted() will. Only log a
103 // time for execution if the script, in fact, executed.
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53104 if (!start_time_.is_null()) {
105 elapsed = timestamp - start_time_;
106 if (async_run_info_)
Kunihiko Sakamotocf8f3b582017-08-29 02:40:21107 async_run_info_->OnCompleted(timestamp, elapsed);
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53108 }
ksakamotocbf167aa2017-03-17 06:45:48109 injection_->OnJsInjectionCompleted(result, elapsed);
110 }
111 }
112
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53113 void WillExecute() override {
114 start_time_ = base::TimeTicks::Now();
115 if (async_run_info_)
116 async_run_info_->WillExecute(start_time_);
117 }
ksakamotocbf167aa2017-03-17 06:45:48118
119 private:
120 base::WeakPtr<ScriptInjection> injection_;
121 base::TimeTicks start_time_;
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53122 scoped_refptr<AsyncScriptsRunInfo> async_run_info_;
ksakamotocbf167aa2017-03-17 06:45:48123};
124
[email protected]c11e6592014-06-27 17:07:34125} // namespace
126
rdevlin.cronind533be962015-10-02 17:01:18127// Watches for the deletion of a RenderFrame, after which is_valid will return
128// false.
129class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
130 public:
131 FrameWatcher(content::RenderFrame* render_frame,
132 ScriptInjection* injection)
133 : content::RenderFrameObserver(render_frame),
134 injection_(injection) {}
135 ~FrameWatcher() override {}
136
137 private:
138 void FrameDetached() override { injection_->invalidate_render_frame(); }
139 void OnDestruct() override { injection_->invalidate_render_frame(); }
140
141 ScriptInjection* injection_;
142
143 DISALLOW_COPY_AND_ASSIGN(FrameWatcher);
144};
145
[email protected]ac2f89372014-06-23 21:44:25146// static
hanxia5c856cf2015-02-13 20:51:58147std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
148 const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
[email protected]0d8d6972014-06-03 22:41:02149
hanxia5c856cf2015-02-13 20:51:58150 for (const auto& iter : isolated_worlds) {
151 if (iter.second == isolated_world_id)
152 return iter.first;
[email protected]3c220782014-05-20 01:59:46153 }
[email protected]ac2f89372014-06-23 21:44:25154 return std::string();
[email protected]3c220782014-05-20 01:59:46155}
156
[email protected]ac2f89372014-06-23 21:44:25157// static
hanxia5c856cf2015-02-13 20:51:58158void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
159 g_isolated_worlds.Get().erase(host_id);
[email protected]3c220782014-05-20 01:59:46160}
161
dchengf6f80662016-04-20 20:26:04162ScriptInjection::ScriptInjection(
163 std::unique_ptr<ScriptInjector> injector,
164 content::RenderFrame* render_frame,
165 std::unique_ptr<const InjectionHost> injection_host,
rdevlin.cronin6fba7ec2016-06-24 16:15:05166 UserScript::RunLocation run_location,
167 bool log_activity)
dchenge59eca1602015-12-18 17:48:00168 : injector_(std::move(injector)),
rdevlin.cronin3e11c9862015-06-04 19:54:25169 render_frame_(render_frame),
dchenge59eca1602015-12-18 17:48:00170 injection_host_(std::move(injection_host)),
[email protected]f8abc6e42014-06-24 21:14:43171 run_location_(run_location),
[email protected]d2056002014-07-03 06:18:06172 request_id_(kInvalidRequestId),
kozyatinskiyc8bc9a582015-03-06 09:33:41173 complete_(false),
rdevlin.cronin3e11c9862015-06-04 19:54:25174 did_inject_js_(false),
rdevlin.cronin6fba7ec2016-06-24 16:15:05175 log_activity_(log_activity),
rdevlin.cronind533be962015-10-02 17:01:18176 frame_watcher_(new FrameWatcher(render_frame, this)),
rdevlin.cronin3e11c9862015-06-04 19:54:25177 weak_ptr_factory_(this) {
hanxi9b841662015-03-04 14:36:41178 CHECK(injection_host_.get());
[email protected]f8abc6e42014-06-24 21:14:43179}
180
181ScriptInjection::~ScriptInjection() {
182 if (!complete_)
rdevlin.cronind533be962015-10-02 17:01:18183 NotifyWillNotInject(ScriptInjector::WONT_INJECT);
[email protected]f8abc6e42014-06-24 21:14:43184}
185
kozyatinskiyc8bc9a582015-03-06 09:33:41186ScriptInjection::InjectionResult ScriptInjection::TryToInject(
187 UserScript::RunLocation current_location,
188 ScriptsRunInfo* scripts_run_info,
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53189 scoped_refptr<AsyncScriptsRunInfo> async_run_info,
rdevlin.cronin4bb32d72015-06-02 21:55:01190 const CompletionCallback& async_completion_callback) {
[email protected]f8abc6e42014-06-24 21:14:43191 if (current_location < run_location_)
kozyatinskiyc8bc9a582015-03-06 09:33:41192 return INJECTION_WAITING; // Wait for the right location.
[email protected]f8abc6e42014-06-24 21:14:43193
kozyatinskiyc8bc9a582015-03-06 09:33:41194 if (request_id_ != kInvalidRequestId) {
195 // We're waiting for permission right now, try again later.
196 return INJECTION_WAITING;
197 }
[email protected]f8abc6e42014-06-24 21:14:43198
hanxi9b841662015-03-04 14:36:41199 if (!injection_host_) {
[email protected]c11e6592014-06-27 17:07:34200 NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
kozyatinskiyc8bc9a582015-03-06 09:33:41201 return INJECTION_FINISHED; // We're done.
[email protected]f8abc6e42014-06-24 21:14:43202 }
203
rdevlin.cronin3e11c9862015-06-04 19:54:25204 blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
hanxi9b841662015-03-04 14:36:41205 switch (injector_->CanExecuteOnFrame(
rdevlin.croninc318b93d2015-09-14 20:22:29206 injection_host_.get(), web_frame,
207 ExtensionFrameHelper::Get(render_frame_)->tab_id())) {
[email protected]23a85362014-07-07 23:26:19208 case PermissionsData::ACCESS_DENIED:
[email protected]c11e6592014-06-27 17:07:34209 NotifyWillNotInject(ScriptInjector::NOT_ALLOWED);
kozyatinskiyc8bc9a582015-03-06 09:33:41210 return INJECTION_FINISHED; // We're done.
[email protected]23a85362014-07-07 23:26:19211 case PermissionsData::ACCESS_WITHHELD:
rdevlin.croninb03d1572015-10-02 02:23:52212 RequestPermissionFromBrowser();
kozyatinskiyc8bc9a582015-03-06 09:33:41213 return INJECTION_WAITING; // Wait around for permission.
[email protected]23a85362014-07-07 23:26:19214 case PermissionsData::ACCESS_ALLOWED:
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53215 InjectionResult result =
216 Inject(scripts_run_info, std::move(async_run_info));
kozyatinskiyc8bc9a582015-03-06 09:33:41217 // If the injection is blocked, we need to set the manager so we can
218 // notify it upon completion.
219 if (result == INJECTION_BLOCKED)
rdevlin.cronin4bb32d72015-06-02 21:55:01220 async_completion_callback_ = async_completion_callback;
kozyatinskiyc8bc9a582015-03-06 09:33:41221 return result;
[email protected]f8abc6e42014-06-24 21:14:43222 }
223
rdevlin.cronin958e9f82015-02-17 21:57:14224 NOTREACHED();
kozyatinskiyc8bc9a582015-03-06 09:33:41225 return INJECTION_FINISHED;
[email protected]f8abc6e42014-06-24 21:14:43226}
227
kozyatinskiyc8bc9a582015-03-06 09:33:41228ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
229 ScriptsRunInfo* scripts_run_info) {
hanxi9b841662015-03-04 14:36:41230 if (!injection_host_) {
[email protected]c11e6592014-06-27 17:07:34231 NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
kozyatinskiyc8bc9a582015-03-06 09:33:41232 return INJECTION_FINISHED;
[email protected]f8abc6e42014-06-24 21:14:43233 }
234
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53235 return Inject(scripts_run_info, nullptr);
[email protected]f8abc6e42014-06-24 21:14:43236}
237
hanxi9b841662015-03-04 14:36:41238void ScriptInjection::OnHostRemoved() {
239 injection_host_.reset(nullptr);
240}
241
rdevlin.croninb03d1572015-10-02 02:23:52242void ScriptInjection::RequestPermissionFromBrowser() {
[email protected]23a85362014-07-07 23:26:19243 // If we are just notifying the browser of the injection, then send an
[email protected]f8abc6e42014-06-24 21:14:43244 // invalid request (which is treated like a notification).
rdevlin.croninb03d1572015-10-02 02:23:52245 request_id_ = g_next_pending_id++;
rdevlin.cronin45dca7f2015-06-08 19:47:03246 render_frame_->Send(new ExtensionHostMsg_RequestScriptInjectionPermission(
rdevlin.cronin8d034e52016-02-02 22:46:32247 render_frame_->GetRoutingID(), host_id().id(), injector_->script_type(),
248 run_location_, request_id_));
[email protected]f8abc6e42014-06-24 21:14:43249}
250
[email protected]c11e6592014-06-27 17:07:34251void ScriptInjection::NotifyWillNotInject(
252 ScriptInjector::InjectFailureReason reason) {
[email protected]f8abc6e42014-06-24 21:14:43253 complete_ = true;
rdevlin.cronind533be962015-10-02 17:01:18254 injector_->OnWillNotInject(reason, render_frame_);
[email protected]f8abc6e42014-06-24 21:14:43255}
256
kozyatinskiyc8bc9a582015-03-06 09:33:41257ScriptInjection::InjectionResult ScriptInjection::Inject(
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53258 ScriptsRunInfo* scripts_run_info,
259 scoped_refptr<AsyncScriptsRunInfo> async_run_info) {
hanxi9b841662015-03-04 14:36:41260 DCHECK(injection_host_);
[email protected]c11e6592014-06-27 17:07:34261 DCHECK(scripts_run_info);
262 DCHECK(!complete_);
catmullingsd4faad4f2016-09-08 19:55:30263 bool should_inject_js = injector_->ShouldInjectJs(
264 run_location_, scripts_run_info->executing_scripts[host_id().id()]);
265 bool should_inject_css = injector_->ShouldInjectCss(
266 run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
[email protected]c11e6592014-06-27 17:07:34267
catmullingsd4faad4f2016-09-08 19:55:30268 // This can happen if the extension specified a script to
269 // be run in multiple rules, and the script has already run.
270 // See crbug.com/631247.
271 if (!should_inject_js && !should_inject_css) {
272 return INJECTION_FINISHED;
273 }
[email protected]c11e6592014-06-27 17:07:34274
rdevlin.cronin4bb32d72015-06-02 21:55:01275 if (should_inject_js)
catmullingsd4faad4f2016-09-08 19:55:30276 InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53277 &(scripts_run_info->num_js), std::move(async_run_info));
rdevlin.cronin4bb32d72015-06-02 21:55:01278 if (should_inject_css)
catmullingsd4faad4f2016-09-08 19:55:30279 InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
280 &(scripts_run_info->num_css));
[email protected]c11e6592014-06-27 17:07:34281
rdevlin.cronin4bb32d72015-06-02 21:55:01282 complete_ = did_inject_js_ || !should_inject_js;
[email protected]c11e6592014-06-27 17:07:34283
rdevlin.cronind533be962015-10-02 17:01:18284 if (complete_) {
dchenge59eca1602015-12-18 17:48:00285 injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
rdevlin.cronind533be962015-10-02 17:01:18286 render_frame_);
287 } else {
rdevlin.cronin4bb32d72015-06-02 21:55:01288 ++scripts_run_info->num_blocking_js;
rdevlin.cronind533be962015-10-02 17:01:18289 }
rdevlin.cronin4bb32d72015-06-02 21:55:01290
kozyatinskiyc8bc9a582015-03-06 09:33:41291 return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
[email protected]c11e6592014-06-27 17:07:34292}
293
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53294void ScriptInjection::InjectJs(
295 std::set<std::string>* executing_scripts,
296 size_t* num_injected_js_scripts,
297 scoped_refptr<AsyncScriptsRunInfo> async_run_info) {
rdevlin.cronin4bb32d72015-06-02 21:55:01298 DCHECK(!did_inject_js_);
rdevlin.cronin3e11c9862015-06-04 19:54:25299 blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
catmullingsd4faad4f2016-09-08 19:55:30300 std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
301 run_location_, executing_scripts, num_injected_js_scripts);
302 DCHECK(!sources.empty());
[email protected]c11e6592014-06-27 17:07:34303 bool in_main_world = injector_->ShouldExecuteInMainWorld();
304 int world_id = in_main_world
305 ? DOMActivityLogger::kMainWorldId
hanxi9b841662015-03-04 14:36:41306 : GetIsolatedWorldIdForInstance(injection_host_.get(),
rdevlin.cronin3e11c9862015-06-04 19:54:25307 web_frame);
kozyatinskiyc8bc9a582015-03-06 09:33:41308 bool is_user_gesture = injector_->IsUserGesture();
309
dchengf6f80662016-04-20 20:26:04310 std::unique_ptr<blink::WebScriptExecutionCallback> callback(
Kunihiko Sakamoto7d386bf2017-07-31 03:19:53311 new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr(),
312 std::move(async_run_info)));
[email protected]c11e6592014-06-27 17:07:34313
314 base::ElapsedTimer exec_timer;
rdevlin.cronin6fba7ec2016-06-24 16:15:05315 if (injection_host_->id().type() == HostID::EXTENSIONS && log_activity_)
hanxi9b841662015-03-04 14:36:41316 DOMActivityLogger::AttachToWorld(world_id, injection_host_->id().id());
[email protected]c11e6592014-06-27 17:07:34317 if (in_main_world) {
318 // We only inject in the main world for javascript: urls.
319 DCHECK_EQ(1u, sources.size());
320
Blink Reformat1c4d759e2017-04-09 16:34:54321 web_frame->RequestExecuteScriptAndReturnValue(
322 sources.front(), is_user_gesture, callback.release());
kozyatinskiyc8bc9a582015-03-06 09:33:41323 } else {
ksakamotocbf167aa2017-03-17 06:45:48324 blink::WebLocalFrame::ScriptExecutionType option;
Kunihiko Sakamotocb2844c92018-03-07 04:31:51325 if (injector_->script_type() == UserScript::CONTENT_SCRIPT) {
ksakamotocbf167aa2017-03-17 06:45:48326 switch (run_location_) {
327 case UserScript::DOCUMENT_END:
328 case UserScript::DOCUMENT_IDLE:
Blink Reformat1c4d759e2017-04-09 16:34:54329 option = blink::WebLocalFrame::kAsynchronousBlockingOnload;
ksakamotocbf167aa2017-03-17 06:45:48330 break;
331 default:
Blink Reformat1c4d759e2017-04-09 16:34:54332 option = blink::WebLocalFrame::kSynchronous;
ksakamotocbf167aa2017-03-17 06:45:48333 break;
334 }
335 } else {
Blink Reformat1c4d759e2017-04-09 16:34:54336 option = blink::WebLocalFrame::kSynchronous;
ksakamotocbf167aa2017-03-17 06:45:48337 }
Blink Reformat1c4d759e2017-04-09 16:34:54338 web_frame->RequestExecuteScriptInIsolatedWorld(
ksakamotocbf167aa2017-03-17 06:45:48339 world_id, &sources.front(), sources.size(), is_user_gesture, option,
rdevlin.cronin3e11c9862015-06-04 19:54:25340 callback.release());
[email protected]c11e6592014-06-27 17:07:34341 }
kozyatinskiyc8bc9a582015-03-06 09:33:41342}
[email protected]c11e6592014-06-27 17:07:34343
kozyatinskiyc8bc9a582015-03-06 09:33:41344void ScriptInjection::OnJsInjectionCompleted(
ksakamotocbf167aa2017-03-17 06:45:48345 const std::vector<v8::Local<v8::Value>>& results,
ksakamoto4178f502017-04-07 04:40:21346 base::Optional<base::TimeDelta> elapsed) {
rdevlin.cronin4bb32d72015-06-02 21:55:01347 DCHECK(!did_inject_js_);
kozyatinskiyc8bc9a582015-03-06 09:33:41348
ksakamoto4178f502017-04-07 04:40:21349 if (injection_host_->id().type() == HostID::EXTENSIONS && elapsed) {
350 UMA_HISTOGRAM_TIMES("Extensions.InjectedScriptExecutionTime", *elapsed);
ksakamoto049f8332017-03-24 06:39:07351 switch (run_location_) {
352 case UserScript::DOCUMENT_START:
353 UMA_HISTOGRAM_TIMES(
ksakamoto4178f502017-04-07 04:40:21354 "Extensions.InjectedScriptExecutionTime.DocumentStart", *elapsed);
ksakamoto049f8332017-03-24 06:39:07355 break;
356 case UserScript::DOCUMENT_END:
357 UMA_HISTOGRAM_TIMES(
ksakamoto4178f502017-04-07 04:40:21358 "Extensions.InjectedScriptExecutionTime.DocumentEnd", *elapsed);
ksakamoto049f8332017-03-24 06:39:07359 break;
360 case UserScript::DOCUMENT_IDLE:
361 UMA_HISTOGRAM_TIMES(
ksakamoto4178f502017-04-07 04:40:21362 "Extensions.InjectedScriptExecutionTime.DocumentIdle", *elapsed);
ksakamoto049f8332017-03-24 06:39:07363 break;
364 default:
365 break;
366 }
367 }
ksakamotocbf167aa2017-03-17 06:45:48368
kozyatinskiyc8bc9a582015-03-06 09:33:41369 bool expects_results = injector_->ExpectsResults();
[email protected]c11e6592014-06-27 17:07:34370 if (expects_results) {
rdevlin.cronin0d94256f2016-12-09 15:34:23371 if (!results.empty() && !results[0].IsEmpty()) {
kozyatinskiyefaa59a2015-04-03 17:57:16372 // Right now, we only support returning single results (per frame).
kozyatinskiyefaa59a2015-04-03 17:57:16373 // It's safe to always use the main world context when converting
374 // here. V8ValueConverterImpl shouldn't actually care about the
375 // context scope, and it switches to v8::Object's creation context
376 // when encountered.
rdevlin.cronin3e11c9862015-06-04 19:54:25377 v8::Local<v8::Context> context =
Blink Reformat1c4d759e2017-04-09 16:34:54378 render_frame_->GetWebFrame()->MainWorldScriptContext();
rdevlin.cronin694c6052017-06-13 22:07:35379 execution_result_ =
380 content::V8ValueConverter::Create()->FromV8Value(results[0], context);
kozyatinskiyefaa59a2015-04-03 17:57:16381 }
rdevlin.cronin4bb32d72015-06-02 21:55:01382 if (!execution_result_.get())
Jeremy Roman16529d0e2017-08-24 18:13:47383 execution_result_ = std::make_unique<base::Value>();
kozyatinskiyc8bc9a582015-03-06 09:33:41384 }
rdevlin.cronin4bb32d72015-06-02 21:55:01385 did_inject_js_ = true;
kozyatinskiyc8bc9a582015-03-06 09:33:41386
rdevlin.cronin4bb32d72015-06-02 21:55:01387 // If |async_completion_callback_| is set, it means the script finished
388 // asynchronously, and we should run it.
389 if (!async_completion_callback_.is_null()) {
ksakamotocbf167aa2017-03-17 06:45:48390 complete_ = true;
dchenge59eca1602015-12-18 17:48:00391 injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
rdevlin.cronind533be962015-10-02 17:01:18392 render_frame_);
rdevlin.cronin4bb32d72015-06-02 21:55:01393 // Warning: this object can be destroyed after this line!
394 async_completion_callback_.Run(this);
[email protected]c11e6592014-06-27 17:07:34395 }
396}
397
catmullingsd4faad4f2016-09-08 19:55:30398void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
399 size_t* num_injected_stylesheets) {
400 std::vector<blink::WebString> css_sources = injector_->GetCssSources(
401 run_location_, injected_stylesheets, num_injected_stylesheets);
rdevlin.cronin3e11c9862015-06-04 19:54:25402 blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
Manish Jethani9494d722018-01-20 00:28:47403 // Default CSS origin is "author", but can be overridden to "user" by scripts.
404 base::Optional<CSSOrigin> css_origin = injector_->GetCssOrigin();
405 blink::WebDocument::CSSOrigin blink_css_origin =
406 css_origin && *css_origin == CSS_ORIGIN_USER
407 ? blink::WebDocument::kUserOrigin
408 : blink::WebDocument::kAuthorOrigin;
Manish Jethaniff6ff852018-02-23 07:24:55409 blink::WebStyleSheetKey style_sheet_key;
410 if (const base::Optional<std::string>& injection_key =
411 injector_->GetInjectionKey())
412 style_sheet_key = blink::WebString::FromASCII(*injection_key);
lazyboy49cc0b3a2016-08-18 21:55:12413 for (const blink::WebString& css : css_sources)
Manish Jethaniff6ff852018-02-23 07:24:55414 web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key,
415 blink_css_origin);
[email protected]f8abc6e42014-06-24 21:14:43416}
417
[email protected]3c220782014-05-20 01:59:46418} // namespace extensions