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

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: Fix GN Issue 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/tab_socket.mojom.h"
11 #include "printing/features/features.h" 17 #include "printing/features/features.h"
18 #include "services/service_manager/public/cpp/interface_provider.h"
19 #include "third_party/WebKit/public/platform/WebIsolatedWorldIds.h"
20 #include "third_party/WebKit/public/web/WebKit.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
22 #include "third_party/WebKit/public/web/WebScriptExecutionCallback.h"
12 23
13 #if BUILDFLAG(ENABLE_BASIC_PRINTING) 24 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
14 #include "components/printing/renderer/print_web_view_helper.h" 25 #include "components/printing/renderer/print_web_view_helper.h"
15 #include "headless/lib/renderer/headless_print_web_view_helper_delegate.h" 26 #include "headless/lib/renderer/headless_print_web_view_helper_delegate.h"
16 #endif 27 #endif
17 28
18 namespace headless { 29 namespace headless {
19 30
20 HeadlessContentRendererClient::HeadlessContentRendererClient() {} 31 HeadlessContentRendererClient::HeadlessContentRendererClient() {}
21 32
22 HeadlessContentRendererClient::~HeadlessContentRendererClient() {} 33 HeadlessContentRendererClient::~HeadlessContentRendererClient() {}
23 34
35 class HeadlessTabSocketBindings
36 : public gin::Wrappable<HeadlessTabSocketBindings>,
37 public content::RenderFrameObserver,
38 public blink::WebScriptExecutionCallback {
39 public:
40 explicit HeadlessTabSocketBindings(content::RenderFrame* render_frame)
41 : content::RenderFrameObserver(render_frame), weak_ptr_factory_(this) {}
42 ~HeadlessTabSocketBindings() override {}
43
44 // content::RenderFrameObserver implementation:
45 void DidCreateScriptContext(v8::Local<v8::Context> context,
46 int world_id) override {
47 if (world_id == content::ISOLATED_WORLD_ID_GLOBAL) {
48 // For the main world only inject TabSocket if
49 // BINDINGS_POLICY_HEADLESS_MAIN_WORLD is set.
50 if (!(render_frame()->GetEnabledBindings() &
51 content::BindingsPolicy::BINDINGS_POLICY_HEADLESS_MAIN_WORLD)) {
52 return;
53 }
54 } else {
55 // For the isolated worlds only inject TabSocket if
56 // BINDINGS_POLICY_HEADLESS_ISOLATED_WORLD is set and the world id falls
57 // within the range reserved for DevTools created isolated worlds.
58 if (!(render_frame()->GetEnabledBindings() &
59 content::BindingsPolicy::BINDINGS_POLICY_HEADLESS_ISOLATED_WORLD)) {
60 return;
61 }
62 if (world_id < blink::kDevToolsFirstIsolatedWorldId ||
63 world_id > blink::kDevToolsLastIsolatedWorldId) {
64 return;
65 }
66 }
67
68 InitializeTabSocketBindings(context);
69 }
70
71 void WillReleaseScriptContext(v8::Local<v8::Context> context,
72 int world_id) override {
73 if (context_ == context) {
74 on_message_callback_.Reset();
75 context_.Reset();
76 }
77 }
78
79 void OnDestruct() override {}
80
81 // gin::WrappableBase implementation:
82 gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
83 v8::Isolate* isolate) override {
84 return gin::Wrappable<HeadlessTabSocketBindings>::GetObjectTemplateBuilder(
85 isolate)
86 .SetMethod("send", &HeadlessTabSocketBindings::SendImpl)
87 .SetProperty("onmessage", &HeadlessTabSocketBindings::GetOnMessage,
88 &HeadlessTabSocketBindings::SetOnMessage);
89 }
90
91 static gin::WrapperInfo kWrapperInfo;
92
93 private:
94 void SendImpl(const std::string& message) {
95 EnsureTabSocketPtr()->SendMessageToEmbedder(message);
96 }
97
98 v8::Local<v8::Value> GetOnMessage() { return GetOnMessageCallback(); }
99
100 void SetOnMessage(v8::Local<v8::Function> callback) {
101 on_message_callback_.Reset(blink::MainThreadIsolate(), callback);
102
103 EnsureTabSocketPtr()->AwaitNextMessageFromEmbedder(
104 base::Bind(&HeadlessTabSocketBindings::OnNextMessageFromEmbedder,
105 weak_ptr_factory_.GetWeakPtr()));
106 }
107
108 void OnNextMessageFromEmbedder(const std::string& message) {
109 v8::Isolate* isolate = blink::MainThreadIsolate();
110 v8::HandleScope handle_scope(isolate);
111 v8::Local<v8::Context> context = GetContext();
112 v8::Local<v8::Value> argv[] = {
113 gin::Converter<std::string>::ToV8(isolate, message),
114 };
115
116 render_frame()->GetWebFrame()->RequestExecuteV8Function(
117 context, GetOnMessageCallback(), context->Global(), arraysize(argv),
118 argv, this);
119 }
120
121 void InitializeTabSocketBindings(v8::Local<v8::Context> context) {
122 // Add TabSocket bindings to the DevTools created isolated world.
123 v8::Isolate* isolate = blink::MainThreadIsolate();
124 v8::HandleScope handle_scope(isolate);
125 if (context.IsEmpty())
126 return;
127
128 v8::Context::Scope context_scope(context);
129 gin::Handle<HeadlessTabSocketBindings> bindings =
130 gin::CreateHandle(isolate, this);
131 if (bindings.IsEmpty())
132 return;
133
134 v8::Local<v8::Object> global = context->Global();
135 global->Set(gin::StringToV8(isolate, "TabSocket"), bindings.ToV8());
136 context_.Reset(blink::MainThreadIsolate(), context);
137 }
138
139 headless::TabSocketPtr& EnsureTabSocketPtr() {
140 if (!tab_socket_ptr_.is_bound()) {
141 render_frame()->GetRemoteInterfaces()->GetInterface(
142 mojo::MakeRequest(&tab_socket_ptr_));
143 }
144 return tab_socket_ptr_;
145 }
146
147 v8::Local<v8::Context> GetContext() {
148 return v8::Local<v8::Context>::New(blink::MainThreadIsolate(), context_);
149 }
150
151 v8::Local<v8::Function> GetOnMessageCallback() {
152 return v8::Local<v8::Function>::New(blink::MainThreadIsolate(),
153 on_message_callback_);
154 }
155
156 headless::TabSocketPtr tab_socket_ptr_;
157 v8::UniquePersistent<v8::Context> context_;
158 v8::UniquePersistent<v8::Function> on_message_callback_;
159 base::WeakPtrFactory<HeadlessTabSocketBindings> weak_ptr_factory_;
160 };
161
162 gin::WrapperInfo HeadlessTabSocketBindings::kWrapperInfo = {
163 gin::kEmbedderNativeGin};
164
24 void HeadlessContentRendererClient::RenderFrameCreated( 165 void HeadlessContentRendererClient::RenderFrameCreated(
25 content::RenderFrame* render_frame) { 166 content::RenderFrame* render_frame) {
26 #if BUILDFLAG(ENABLE_BASIC_PRINTING) 167 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
27 new printing::PrintWebViewHelper( 168 new printing::PrintWebViewHelper(
28 render_frame, base::MakeUnique<HeadlessPrintWebViewHelperDelegate>()); 169 render_frame, base::MakeUnique<HeadlessPrintWebViewHelperDelegate>());
29 #endif 170 #endif
30 } 171 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 } 172 }
96 173
97 } // namespace headless 174 } // namespace headless
OLDNEW
« no previous file with comments | « headless/lib/renderer/headless_content_renderer_client.h ('k') | headless/public/headless_web_contents.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698