4b8bf99666c53058670ab5869bdbde1d0925de1e
[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/JSONValues.h>
35 #include <wtf/MainThread.h>
36 #include <wtf/NeverDestroyed.h>
37 #include <wtf/RunLoop.h>
38
39 namespace Inspector {
40
41 PlatformSocketType RemoteInspector::s_connectionIdentifier = INVALID_SOCKET_VALUE;
42 uint16_t RemoteInspector::s_serverPort = 0;
43
44 RemoteInspector& RemoteInspector::singleton()
45 {
46     static NeverDestroyed<RemoteInspector> shared;
47     return shared;
48 }
49
50 RemoteInspector::RemoteInspector()
51 {
52     Socket::init();
53     start();
54 }
55
56 void RemoteInspector::didClose(ConnectionID id)
57 {
58     if (id != m_clientID.value())
59         return;
60
61     RunLoop::current().dispatch([=] {
62         LockHolder lock(m_mutex);
63         stopInternal(StopSource::API);
64     });
65 }
66
67 HashMap<String, RemoteInspector::CallHandler>& RemoteInspector::dispatchMap()
68 {
69     static NeverDestroyed<HashMap<String, CallHandler>> methods = HashMap<String, CallHandler>({
70         { "GetTargetList"_s, static_cast<CallHandler>(&RemoteInspector::receivedGetTargetListMessage) },
71         { "Setup"_s, static_cast<CallHandler>(&RemoteInspector::receivedSetupMessage) },
72         { "SendMessageToTarget"_s, static_cast<CallHandler>(&RemoteInspector::receivedDataMessage) },
73         { "FrontendDidClose"_s, static_cast<CallHandler>(&RemoteInspector::receivedCloseMessage) },
74     });
75
76     return methods;
77 }
78
79 void RemoteInspector::sendWebInspectorEvent(const String& event)
80 {
81     if (!m_clientID)
82         return;
83
84     const CString message = event.utf8();
85     send(m_clientID.value(), reinterpret_cast<const uint8_t*>(message.data()), message.length());
86 }
87
88 void RemoteInspector::start()
89 {
90     LockHolder lock(m_mutex);
91
92     if (m_enabled || (s_connectionIdentifier == INVALID_SOCKET_VALUE && !s_serverPort))
93         return;
94
95     m_enabled = true;
96
97     if (s_connectionIdentifier != INVALID_SOCKET_VALUE) {
98         m_clientID = createClient(s_connectionIdentifier);
99         s_connectionIdentifier = INVALID_SOCKET_VALUE;
100     } else
101         m_clientID = connectInet("127.0.0.1", s_serverPort);
102
103     if (!m_targetMap.isEmpty())
104         pushListingsSoon();
105 }
106
107 void RemoteInspector::stopInternal(StopSource)
108 {
109     if (!m_enabled)
110         return;
111
112     m_enabled = false;
113     m_pushScheduled = false;
114
115     for (auto targetConnection : m_targetConnectionMap.values())
116         targetConnection->close();
117     m_targetConnectionMap.clear();
118
119     updateHasActiveDebugSession();
120
121     m_automaticInspectionPaused = false;
122     m_clientID = WTF::nullopt;
123 }
124
125 TargetListing RemoteInspector::listingForInspectionTarget(const RemoteInspectionTarget& target) const
126 {
127     if (!target.remoteDebuggingAllowed())
128         return nullptr;
129
130     // FIXME: Support remote debugging of a ServiceWorker.
131     if (target.type() == RemoteInspectionTarget::Type::ServiceWorker)
132         return nullptr;
133
134     TargetListing targetListing = JSON::Object::create();
135
136     targetListing->setString("name"_s, target.name());
137     targetListing->setString("url"_s, target.url());
138     targetListing->setInteger("targetID"_s, target.targetIdentifier());
139     targetListing->setBoolean("hasLocalDebugger"_s, target.hasLocalDebugger());
140     if (target.type() == RemoteInspectionTarget::Type::Web)
141         targetListing->setString("type"_s, "web"_s);
142     else if (target.type() == RemoteInspectionTarget::Type::JavaScript)
143         targetListing->setString("type"_s, "javascript"_s);
144     else if (target.type() == RemoteInspectionTarget::Type::ServiceWorker)
145         targetListing->setString("type"_s, "service-worker"_s);
146
147     return targetListing;
148 }
149
150 TargetListing RemoteInspector::listingForAutomationTarget(const RemoteAutomationTarget&) const
151 {
152     return nullptr;
153 }
154
155 void RemoteInspector::pushListingsNow()
156 {
157     if (!m_clientID)
158         return;
159
160     m_pushScheduled = false;
161
162     auto targetListJSON = JSON::Array::create();
163     for (auto listing : m_targetListingMap.values())
164         targetListJSON->pushObject(listing);
165
166     auto jsonEvent = JSON::Object::create();
167     jsonEvent->setString("event"_s, "SetTargetList"_s);
168     jsonEvent->setString("message"_s, targetListJSON->toJSONString());
169     sendWebInspectorEvent(jsonEvent->toJSONString());
170 }
171
172 void RemoteInspector::pushListingsSoon()
173 {
174     if (!m_clientID)
175         return;
176
177     if (m_pushScheduled)
178         return;
179
180     m_pushScheduled = true;
181
182     RunLoop::current().dispatch([=] {
183         LockHolder lock(m_mutex);
184         if (m_pushScheduled)
185             pushListingsNow();
186     });
187 }
188
189 void RemoteInspector::sendAutomaticInspectionCandidateMessage()
190 {
191 }
192
193 void RemoteInspector::sendMessageToRemote(TargetID targetIdentifier, const String& message)
194 {
195     LockHolder lock(m_mutex);
196     if (!m_clientID)
197         return;
198
199     auto sendMessageEvent = JSON::Object::create();
200     sendMessageEvent->setInteger("targetID"_s, targetIdentifier);
201     sendMessageEvent->setString("event"_s, "SendMessageToFrontend"_s);
202     sendMessageEvent->setString("message"_s, message);
203     sendWebInspectorEvent(sendMessageEvent->toJSONString());
204 }
205
206 void RemoteInspector::receivedGetTargetListMessage(const Event&)
207 {
208     ASSERT(isMainThread());
209
210     LockHolder lock(m_mutex);
211     pushListingsNow();
212 }
213
214 void RemoteInspector::receivedSetupMessage(const Event& event)
215 {
216     ASSERT(isMainThread());
217
218     if (event.targetID)
219         setup(event.targetID.value());
220 }
221
222 void RemoteInspector::receivedDataMessage(const Event& event)
223 {
224     ASSERT(isMainThread());
225
226     if (!event.targetID || !event.message)
227         return;
228
229     RefPtr<RemoteConnectionToTarget> connectionToTarget;
230     {
231         LockHolder lock(m_mutex);
232         connectionToTarget = m_targetConnectionMap.get(event.targetID.value());
233         if (!connectionToTarget)
234             return;
235     }
236
237     connectionToTarget->sendMessageToTarget(event.message.value());
238 }
239
240 void RemoteInspector::receivedCloseMessage(const Event& event)
241 {
242     ASSERT(isMainThread());
243
244     if (!event.targetID)
245         return;
246
247     RefPtr<RemoteConnectionToTarget> connectionToTarget;
248     {
249         LockHolder lock(m_mutex);
250         RemoteControllableTarget* target = m_targetMap.get(event.targetID.value());
251         if (!target)
252             return;
253
254         connectionToTarget = m_targetConnectionMap.take(event.targetID.value());
255         updateHasActiveDebugSession();
256     }
257
258     if (connectionToTarget)
259         connectionToTarget->close();
260 }
261
262 void RemoteInspector::setup(TargetID targetIdentifier)
263 {
264     RemoteControllableTarget* target;
265     {
266         LockHolder lock(m_mutex);
267         target = m_targetMap.get(targetIdentifier);
268         if (!target)
269             return;
270     }
271
272     auto connectionToTarget = adoptRef(*new RemoteConnectionToTarget(*target));
273     ASSERT(is<RemoteInspectionTarget>(target) || is<RemoteAutomationTarget>(target));
274     if (!connectionToTarget->setup()) {
275         connectionToTarget->close();
276         return;
277     }
278
279     LockHolder lock(m_mutex);
280     m_targetConnectionMap.set(targetIdentifier, WTFMove(connectionToTarget));
281
282     updateHasActiveDebugSession();
283 }
284
285 void RemoteInspector::sendMessageToTarget(TargetID targetIdentifier, const char* message)
286 {
287     if (auto connectionToTarget = m_targetConnectionMap.get(targetIdentifier))
288         connectionToTarget->sendMessageToTarget(String::fromUTF8(message));
289 }
290
291 void RemoteInspector::setConnectionIdentifier(PlatformSocketType connectionIdentifier)
292 {
293     RemoteInspector::s_connectionIdentifier = connectionIdentifier;
294 }
295
296 void RemoteInspector::setServerPort(uint16_t port)
297 {
298     RemoteInspector::s_serverPort = port;
299 }
300
301 } // namespace Inspector
302
303 #endif // ENABLE(REMOTE_INSPECTOR)