[WinCairo] Move remote communication handling from RemoteInspectorServer to RemoteIns...
[WebKit.git] / Source / JavaScriptCore / inspector / remote / socket / RemoteInspectorSocket.cpp
1 /*
2  * Copyright (C) 2019 Sony Interactive Entertainment Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "RemoteInspector.h"
28
29 #if ENABLE(REMOTE_INSPECTOR)
30
31 #include "RemoteAutomationTarget.h"
32 #include "RemoteConnectionToTarget.h"
33 #include "RemoteInspectionTarget.h"
34 #include <wtf/FileSystem.h>
35 #include <wtf/JSONValues.h>
36 #include <wtf/MainThread.h>
37 #include <wtf/NeverDestroyed.h>
38 #include <wtf/RunLoop.h>
39
40 namespace Inspector {
41
42 RemoteInspector& RemoteInspector::singleton()
43 {
44     static NeverDestroyed<RemoteInspector> shared;
45     return shared;
46 }
47
48 RemoteInspector::RemoteInspector()
49 {
50     Socket::init();
51     start();
52 }
53
54 void RemoteInspector::connect(ConnectionID id)
55 {
56     ASSERT(!isConnected());
57
58     m_clientConnection = id;
59     start();
60 }
61
62 void RemoteInspector::didClose(ConnectionID)
63 {
64     ASSERT(isConnected());
65
66     m_clientConnection = WTF::nullopt;
67
68     RunLoop::current().dispatch([=] {
69         LockHolder lock(m_mutex);
70         stopInternal(StopSource::API);
71     });
72 }
73
74 void RemoteInspector::sendWebInspectorEvent(const String& event)
75 {
76     if (!m_clientConnection)
77         return;
78
79     const CString message = event.utf8();
80     send(m_clientConnection.value(), reinterpret_cast<const uint8_t*>(message.data()), message.length());
81 }
82
83 void RemoteInspector::start()
84 {
85     LockHolder lock(m_mutex);
86
87     if (m_enabled)
88         return;
89
90     m_enabled = true;
91 }
92
93 void RemoteInspector::stopInternal(StopSource)
94 {
95     if (!m_enabled)
96         return;
97
98     m_enabled = false;
99     m_pushScheduled = false;
100     m_readyToPushListings = false;
101
102     for (auto targetConnection : m_targetConnectionMap.values())
103         targetConnection->close();
104     m_targetConnectionMap.clear();
105
106     updateHasActiveDebugSession();
107
108     m_automaticInspectionPaused = false;
109 }
110
111 TargetListing RemoteInspector::listingForInspectionTarget(const RemoteInspectionTarget& target) const
112 {
113     if (!target.remoteDebuggingAllowed())
114         return nullptr;
115
116     // FIXME: Support remote debugging of a ServiceWorker.
117     if (target.type() == RemoteInspectionTarget::Type::ServiceWorker)
118         return nullptr;
119
120     TargetListing targetListing = JSON::Object::create();
121
122     targetListing->setString("name"_s, target.name());
123     targetListing->setString("url"_s, target.url());
124     targetListing->setInteger("targetID"_s, target.targetIdentifier());
125     targetListing->setBoolean("hasLocalDebugger"_s, target.hasLocalDebugger());
126     if (target.type() == RemoteInspectionTarget::Type::Web)
127         targetListing->setString("type"_s, "web"_s);
128     else if (target.type() == RemoteInspectionTarget::Type::JavaScript)
129         targetListing->setString("type"_s, "javascript"_s);
130     else if (target.type() == RemoteInspectionTarget::Type::ServiceWorker)
131         targetListing->setString("type"_s, "service-worker"_s);
132
133     return targetListing;
134 }
135
136 TargetListing RemoteInspector::listingForAutomationTarget(const RemoteAutomationTarget&) const
137 {
138     return nullptr;
139 }
140
141 void RemoteInspector::pushListingsNow()
142 {
143     if (!isConnected() || !m_readyToPushListings)
144         return;
145
146     m_pushScheduled = false;
147
148     auto targetListJSON = JSON::Array::create();
149     for (auto listing : m_targetListingMap.values())
150         targetListJSON->pushObject(listing);
151
152     auto jsonEvent = JSON::Object::create();
153     jsonEvent->setString("event"_s, "SetTargetList"_s);
154     jsonEvent->setString("message"_s, targetListJSON->toJSONString());
155     jsonEvent->setInteger("connectionID"_s, m_clientConnection.value());
156     jsonEvent->setBoolean("remoteAutomationAllowed"_s, m_clientCapabilities && m_clientCapabilities->remoteAutomationAllowed);
157     sendWebInspectorEvent(jsonEvent->toJSONString());
158 }
159
160 void RemoteInspector::pushListingsSoon()
161 {
162     if (!isConnected())
163         return;
164
165     if (m_pushScheduled)
166         return;
167
168     m_pushScheduled = true;
169
170     RunLoop::current().dispatch([=] {
171         LockHolder lock(m_mutex);
172         if (m_pushScheduled)
173             pushListingsNow();
174     });
175 }
176
177 void RemoteInspector::sendAutomaticInspectionCandidateMessage()
178 {
179 }
180
181 void RemoteInspector::sendMessageToRemote(TargetID targetIdentifier, const String& message)
182 {
183     if (!m_clientConnection)
184         return;
185
186     auto sendMessageEvent = JSON::Object::create();
187     sendMessageEvent->setInteger("targetID"_s, targetIdentifier);
188     sendMessageEvent->setString("event"_s, "SendMessageToFrontend"_s);
189     sendMessageEvent->setInteger("connectionID"_s, m_clientConnection.value());
190     sendMessageEvent->setString("message"_s, message);
191     sendWebInspectorEvent(sendMessageEvent->toJSONString());
192 }
193
194 void RemoteInspector::setup(TargetID targetIdentifier)
195 {
196     RemoteControllableTarget* target;
197     {
198         LockHolder lock(m_mutex);
199         target = m_targetMap.get(targetIdentifier);
200         if (!target)
201             return;
202     }
203
204     auto connectionToTarget = adoptRef(*new RemoteConnectionToTarget(*target));
205     ASSERT(is<RemoteInspectionTarget>(target) || is<RemoteAutomationTarget>(target));
206     if (!connectionToTarget->setup()) {
207         connectionToTarget->close();
208         return;
209     }
210
211     LockHolder lock(m_mutex);
212     m_targetConnectionMap.set(targetIdentifier, WTFMove(connectionToTarget));
213
214     updateHasActiveDebugSession();
215 }
216
217 void RemoteInspector::sendMessageToTarget(TargetID targetIdentifier, const char* message)
218 {
219     if (auto connectionToTarget = m_targetConnectionMap.get(targetIdentifier))
220         connectionToTarget->sendMessageToTarget(String::fromUTF8(message));
221 }
222
223 String RemoteInspector::backendCommands() const
224 {
225     if (m_backendCommandsPath.isEmpty())
226         return { };
227
228     auto handle = FileSystem::openFile(m_backendCommandsPath, FileSystem::FileOpenMode::Read);
229     if (!FileSystem::isHandleValid(handle))
230         return { };
231
232     String result;
233     long long size;
234     if (FileSystem::getFileSize(handle, size)) {
235         Vector<LChar> buffer(size);
236         if (FileSystem::readFromFile(handle, reinterpret_cast<char*>(buffer.data()), size) == size)
237             result = String::adopt(WTFMove(buffer));
238     }
239     FileSystem::closeFile(handle);
240     return result;
241 }
242
243 // RemoteInspectorConnectionClient handlers
244
245 HashMap<String, RemoteInspectorConnectionClient::CallHandler>& RemoteInspector::dispatchMap()
246 {
247     static NeverDestroyed<HashMap<String, CallHandler>> methods = HashMap<String, CallHandler>({
248         { "SetupInspectorClient"_s, static_cast<CallHandler>(&RemoteInspector::setupInspectorClient) },
249         { "Setup"_s, static_cast<CallHandler>(&RemoteInspector::setupTarget) },
250         { "FrontendDidClose"_s, static_cast<CallHandler>(&RemoteInspector::frontendDidClose) },
251         { "SendMessageToBackend"_s, static_cast<CallHandler>(&RemoteInspector::sendMessageToBackend) },
252     });
253
254     return methods;
255 }
256
257 void RemoteInspector::setupInspectorClient(const Event&)
258 {
259     ASSERT(isMainThread());
260
261     auto backendCommandsEvent = JSON::Object::create();
262     backendCommandsEvent->setString("event"_s, "BackendCommands"_s);
263     backendCommandsEvent->setString("message"_s, backendCommands());
264     sendWebInspectorEvent(backendCommandsEvent->toJSONString());
265
266     m_readyToPushListings = true;
267
268     LockHolder lock(m_mutex);
269     pushListingsNow();
270 }
271
272 void RemoteInspector::setupTarget(const Event& event)
273 {
274     ASSERT(isMainThread());
275
276     if (!event.targetID || !event.connectionID)
277         return;
278
279     setup(event.targetID.value());
280 }
281
282 void RemoteInspector::frontendDidClose(const Event& event)
283 {
284     ASSERT(isMainThread());
285
286     if (!event.targetID)
287         return;
288
289     RefPtr<RemoteConnectionToTarget> connectionToTarget;
290     {
291         LockHolder lock(m_mutex);
292         RemoteControllableTarget* target = m_targetMap.get(event.targetID.value());
293         if (!target)
294             return;
295
296         connectionToTarget = m_targetConnectionMap.take(event.targetID.value());
297         updateHasActiveDebugSession();
298     }
299
300     if (connectionToTarget)
301         connectionToTarget->close();
302 }
303
304 void RemoteInspector::sendMessageToBackend(const Event& event)
305 {
306     ASSERT(isMainThread());
307
308     if (!event.connectionID || !event.targetID || !event.message)
309         return;
310
311     RefPtr<RemoteConnectionToTarget> connectionToTarget;
312     {
313         LockHolder lock(m_mutex);
314         connectionToTarget = m_targetConnectionMap.get(event.targetID.value());
315         if (!connectionToTarget)
316             return;
317     }
318
319     connectionToTarget->sendMessageToTarget(event.message.value());
320 }
321
322 } // namespace Inspector
323
324 #endif // ENABLE(REMOTE_INSPECTOR)