Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: headless/lib/renderer/headless_content_renderer_client.cc

Issue 2873283002: [Reland] Allow headless TabSocket in isolated worlds & remove obsolete logic (Closed)
Patch Set: Changes for Sami Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "headless/lib/renderer/headless_content_renderer_client.h" 5 #include "headless/lib/renderer/headless_content_renderer_client.h"
6 6
7 #include "base/memory/ptr_util.h" 7 #include "base/memory/ptr_util.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "content/public/common/bindings_policy.h" 9 #include "content/public/common/bindings_policy.h"
10 #include "content/public/common/isolated_world_ids.h"
10 #include "content/public/renderer/render_frame.h" 11 #include "content/public/renderer/render_frame.h"
12 #include "content/public/renderer/render_frame_observer.h"
13 #include "gin/handle.h"
14 #include "gin/object_template_builder.h"
15 #include "gin/wrappable.h"
16 #include "headless/lib/renderer/devtools_isolated_world_ids.h"
17 #include "headless/lib/tab_socket.mojom.h"
11 #include "printing/features/features.h" 18 #include "printing/features/features.h"
19 #include "services/service_manager/public/cpp/interface_provider.h"
20 #include "third_party/WebKit/public/web/WebKit.h"
12 21
13 #if BUILDFLAG(ENABLE_BASIC_PRINTING) 22 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
14 #include "components/printing/renderer/print_web_view_helper.h" 23 #include "components/printing/renderer/print_web_view_helper.h"
15 #include "headless/lib/renderer/headless_print_web_view_helper_delegate.h" 24 #include "headless/lib/renderer/headless_print_web_view_helper_delegate.h"
16 #endif 25 #endif
17 26
18 namespace headless { 27 namespace headless {
19 28
20 HeadlessContentRendererClient::HeadlessContentRendererClient() {} 29 HeadlessContentRendererClient::HeadlessContentRendererClient() {}
21 30
22 HeadlessContentRendererClient::~HeadlessContentRendererClient() {} 31 HeadlessContentRendererClient::~HeadlessContentRendererClient() {}
23 32
33 class HeadlessTabSocketBindings
34 : public gin::Wrappable<HeadlessTabSocketBindings>,
35 public content::RenderFrameObserver {
36 public:
37 explicit HeadlessTabSocketBindings(content::RenderFrame* render_frame)
38 : content::RenderFrameObserver(render_frame), weak_ptr_factory_(this) {}
39 ~HeadlessTabSocketBindings() override {}
40
41 // content::RenderFrameObserver implementation:
42 void DidCreateScriptContext(v8::Local<v8::Context> context,
43 int world_id) override {
44 if (world_id == content::ISOLATED_WORLD_ID_GLOBAL) {
45 // For the main world only inject TabSocket if
46 // BINDINGS_POLICY_HEADLESS_MAIN_WORLD is set.
47 if (!(render_frame()->GetEnabledBindings() &
48 content::BindingsPolicy::BINDINGS_POLICY_HEADLESS_MAIN_WORLD)) {
49 return;
50 }
51 } else {
52 // For the isolated worlds only inject TabSocket if
53 // BINDINGS_POLICY_HEADLESS_ISOLATED_WORLD is set and the world id falls
54 // within the range reserved for DevTools created isolated worlds.
55 if (!(render_frame()->GetEnabledBindings() &
56 content::BindingsPolicy::BINDINGS_POLICY_HEADLESS_ISOLATED_WORLD)) {
57 return;
58 }
59 if (world_id < kDevToolsFirstIsolatedWorldId ||
60 world_id > kDevToolsLastIsolatedWorldId) {
61 return;
62 }
63 }
64
65 InitializeTabSocketBindings(context);
66 }
67
68 void WillReleaseScriptContext(v8::Local<v8::Context> context,
69 int world_id) override {
70 if (context_ == context) {
71 on_message_callback_.Reset();
72 context_.Reset();
73 }
74 }
75
76 void OnDestruct() override {}
77
78 // gin::WrappableBase implementation:
79 gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
80 v8::Isolate* isolate) override {
81 return gin::Wrappable<HeadlessTabSocketBindings>::GetObjectTemplateBuilder(
82 isolate)
83 .SetMethod("send", &HeadlessTabSocketBindings::SendImpl)
84 .SetProperty("onmessage", &HeadlessTabSocketBindings::GetOnMessage,
85 &HeadlessTabSocketBindings::SetOnMessage);
86 }
87
88 static gin::WrapperInfo kWrapperInfo;
89
90 private:
91 void SendImpl(const std::string& message) {
92 EnsureTabSocketPtr()->SendMessageToEmbedder(message);
93 }
94
95 v8::Local<v8::Value> GetOnMessage() { return GetOnMessageCallback(); }
96
97 void SetOnMessage(v8::Local<v8::Function> callback) {
98 on_message_callback_.Reset(blink::MainThreadIsolate(), callback);
99
100 EnsureTabSocketPtr()->AwaitNextMessageFromEmbedder(
101 base::Bind(&HeadlessTabSocketBindings::OnNextMessageFromEmbedder,
102 weak_ptr_factory_.GetWeakPtr()));
103 }
104
105 void OnNextMessageFromEmbedder(const std::string& message) {
106 CallOnMessageCallback(message);
107 }
108
109 v8::Local<v8::Value> CallOnMessageCallback(const std::string& message) {
110 v8::Isolate* isolate = blink::MainThreadIsolate();
111 v8::HandleScope handle_scope(isolate);
112 v8::Local<v8::Context> context = GetContext();
113 v8::Context::Scope context_scope(context);
114 v8::Local<v8::Value> argv[] = {
115 gin::Converter<std::string>::ToV8(isolate, message),
116 };
117 v8::TryCatch try_catch(isolate);
118 v8::MicrotasksScope microtasks(isolate,
119 v8::MicrotasksScope::kDoNotRunMicrotasks);
120
121 v8::MaybeLocal<v8::Value> maybe_result = GetOnMessageCallback()->Call(
122 context, context->Global(), arraysize(argv), argv);
jochen (gone - plz use gerrit) 2017/05/19 13:33:13 this should probably use WebLocalFrame::requestExe
alex clarke (OOO till 29th) 2017/05/19 14:53:01 The TabSocket lets us do this: TabSocket.onmessag
123
124 v8::Local<v8::Value> result;
125 if (!maybe_result.ToLocal(&result))
126 return v8::Local<v8::Value>();
127 return result;
128 }
129
130 void InitializeTabSocketBindings(v8::Local<v8::Context> context) {
131 // Add TabSocket bindings to the DevTools created isolated world.
132 v8::Isolate* isolate = blink::MainThreadIsolate();
133 v8::HandleScope handle_scope(isolate);
134 if (context.IsEmpty())
135 return;
136
137 v8::Context::Scope context_scope(context);
138 gin::Handle<HeadlessTabSocketBindings> bindings =
139 gin::CreateHandle(isolate, this);
140 if (bindings.IsEmpty())
141 return;
142
143 v8::Local<v8::Object> global = context->Global();
144 global->Set(gin::StringToV8(isolate, "TabSocket"), bindings.ToV8());
145 context_.Reset(blink::MainThreadIsolate(), context);
146 }
147
148 headless::TabSocketPtr& EnsureTabSocketPtr() {
149 if (!tab_socket_ptr_.is_bound()) {
150 render_frame()->GetRemoteInterfaces()->GetInterface(
151 mojo::MakeRequest(&tab_socket_ptr_));
152 }
153 return tab_socket_ptr_;
154 }
155
156 v8::Local<v8::Context> GetContext() {
157 return v8::Local<v8::Context>::New(blink::MainThreadIsolate(), context_);
158 }
159
160 v8::Local<v8::Function> GetOnMessageCallback() {
161 return v8::Local<v8::Function>::New(blink::MainThreadIsolate(),
162 on_message_callback_);
163 }
164
165 headless::TabSocketPtr tab_socket_ptr_;
166 v8::UniquePersistent<v8::Context> context_;
167 v8::UniquePersistent<v8::Function> on_message_callback_;
168 base::WeakPtrFactory<HeadlessTabSocketBindings> weak_ptr_factory_;
169 };
170
171 gin::WrapperInfo HeadlessTabSocketBindings::kWrapperInfo = {
172 gin::kEmbedderNativeGin};
173
24 void HeadlessContentRendererClient::RenderFrameCreated( 174 void HeadlessContentRendererClient::RenderFrameCreated(
25 content::RenderFrame* render_frame) { 175 content::RenderFrame* render_frame) {
26 #if BUILDFLAG(ENABLE_BASIC_PRINTING) 176 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
27 new printing::PrintWebViewHelper( 177 new printing::PrintWebViewHelper(
28 render_frame, base::MakeUnique<HeadlessPrintWebViewHelperDelegate>()); 178 render_frame, base::MakeUnique<HeadlessPrintWebViewHelperDelegate>());
29 #endif 179 #endif
30 } 180 new HeadlessTabSocketBindings(render_frame);
31
32 void HeadlessContentRendererClient::RunScriptsAtDocumentStart(
33 content::RenderFrame* render_frame) {
34 if (!(render_frame->GetEnabledBindings() &
35 content::BindingsPolicy::BINDINGS_POLICY_HEADLESS)) {
36 return;
37 }
38
39 render_frame->ExecuteJavaScript(base::UTF8ToUTF16(R"(
40 (function() {
41 let tabSocket = null;
42 let messagesToSend = [];
43
44 function getNextEmbedderMessage() {
45 tabSocket.awaitNextMessageFromEmbedder().then(
46 function(result) {
47 window.TabSocket.onmessage(new CustomEvent(
48 "onmessage", {detail : {message : result.message}}));
49 getNextEmbedderMessage();
50 });
51 };
52
53 window.TabSocket = new Proxy(
54 {
55 send: function(message) {
56 if (tabSocket) {
57 tabSocket.sendMessageToEmbedder(message);
58 } else {
59 messagesToSend.push(message);
60 }
61 },
62 onmessage: null
63 },
64 {
65 set: function(target, prop, value, receiver) {
66 if (prop !== "onmessage")
67 return false;
68 target[prop] = value;
69 if (tabSocket)
70 getNextEmbedderMessage();
71 return true;
72 }
73 });
74
75 // Note define() defines a module in the mojo module dependency
76 // system. While we don't expose our module, the callback below only
77 // fires after the requested modules have been loaded.
78 define([
79 'headless/lib/tab_socket.mojom',
80 'content/public/renderer/frame_interfaces',
81 ], function(tabSocketMojom, frameInterfaces) {
82 tabSocket = new tabSocketMojom.TabSocketPtr(
83 frameInterfaces.getInterface(tabSocketMojom.TabSocket.name));
84 // Send any messages that may have been created before the dependency
85 // was resolved.
86 for (var i = 0; i < messagesToSend.length; i++) {
87 tabSocket.sendMessageToEmbedder(messagesToSend[i]);
88 }
89 messagesToSend = [];
90 if (window.TabSocket.onmessage)
91 getNextEmbedderMessage();
92 });
93
94 })(); )"));
95 } 181 }
96 182
97 } // namespace headless 183 } // namespace headless
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698