11cb0ef41Sopenharmony_ci#include "inspector_socket_server.h" 21cb0ef41Sopenharmony_ci#include <unistd.h> 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ci#include "node.h" 51cb0ef41Sopenharmony_ci#include "util-inl.h" 61cb0ef41Sopenharmony_ci#include "uv.h" 71cb0ef41Sopenharmony_ci#include "zlib.h" 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include <algorithm> 101cb0ef41Sopenharmony_ci#include <cstdio> 111cb0ef41Sopenharmony_ci#include <iostream> 121cb0ef41Sopenharmony_ci#include <map> 131cb0ef41Sopenharmony_ci#include <set> 141cb0ef41Sopenharmony_ci#include <sstream> 151cb0ef41Sopenharmony_ci#include <string> 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_cinamespace node { 181cb0ef41Sopenharmony_cinamespace inspector { 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci// Function is declared in inspector_io.h so the rest of the node does not 211cb0ef41Sopenharmony_ci// depend on inspector_socket_server.h 221cb0ef41Sopenharmony_cistd::string FormatWsAddress(const std::string& host, int port, 231cb0ef41Sopenharmony_ci const std::string& target_id, 241cb0ef41Sopenharmony_ci bool include_protocol); 251cb0ef41Sopenharmony_cinamespace { 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_cistatic const uint8_t PROTOCOL_JSON[] = { 281cb0ef41Sopenharmony_ci #include "v8_inspector_protocol_json.h" // NOLINT(build/include_order) 291cb0ef41Sopenharmony_ci}; 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_civoid Escape(std::string* string) { 321cb0ef41Sopenharmony_ci for (char& c : *string) { 331cb0ef41Sopenharmony_ci c = (c == '\"' || c == '\\') ? '_' : c; 341cb0ef41Sopenharmony_ci } 351cb0ef41Sopenharmony_ci} 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_cistd::string FormatHostPort(const std::string& host, int port) { 381cb0ef41Sopenharmony_ci // Host is valid (socket was bound) so colon means it's a v6 IP address 391cb0ef41Sopenharmony_ci bool v6 = host.find(':') != std::string::npos; 401cb0ef41Sopenharmony_ci std::ostringstream url; 411cb0ef41Sopenharmony_ci if (v6) { 421cb0ef41Sopenharmony_ci url << '['; 431cb0ef41Sopenharmony_ci } 441cb0ef41Sopenharmony_ci url << host; 451cb0ef41Sopenharmony_ci if (v6) { 461cb0ef41Sopenharmony_ci url << ']'; 471cb0ef41Sopenharmony_ci } 481cb0ef41Sopenharmony_ci url << ':' << port; 491cb0ef41Sopenharmony_ci return url.str(); 501cb0ef41Sopenharmony_ci} 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_cistd::string FormatAddress(const std::string& host, 531cb0ef41Sopenharmony_ci const std::string& target_id, 541cb0ef41Sopenharmony_ci bool include_protocol) { 551cb0ef41Sopenharmony_ci std::ostringstream url; 561cb0ef41Sopenharmony_ci if (include_protocol) 571cb0ef41Sopenharmony_ci url << "ws://"; 581cb0ef41Sopenharmony_ci url << host << '/' << target_id; 591cb0ef41Sopenharmony_ci return url.str(); 601cb0ef41Sopenharmony_ci} 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_cistd::string MapToString(const std::map<std::string, std::string>& object) { 631cb0ef41Sopenharmony_ci bool first = true; 641cb0ef41Sopenharmony_ci std::ostringstream json; 651cb0ef41Sopenharmony_ci json << "{\n"; 661cb0ef41Sopenharmony_ci for (const auto& name_value : object) { 671cb0ef41Sopenharmony_ci if (!first) 681cb0ef41Sopenharmony_ci json << ",\n"; 691cb0ef41Sopenharmony_ci first = false; 701cb0ef41Sopenharmony_ci json << " \"" << name_value.first << "\": \""; 711cb0ef41Sopenharmony_ci json << name_value.second << "\""; 721cb0ef41Sopenharmony_ci } 731cb0ef41Sopenharmony_ci json << "\n} "; 741cb0ef41Sopenharmony_ci return json.str(); 751cb0ef41Sopenharmony_ci} 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_cistd::string MapsToString( 781cb0ef41Sopenharmony_ci const std::vector<std::map<std::string, std::string>>& array) { 791cb0ef41Sopenharmony_ci bool first = true; 801cb0ef41Sopenharmony_ci std::ostringstream json; 811cb0ef41Sopenharmony_ci json << "[ "; 821cb0ef41Sopenharmony_ci for (const auto& object : array) { 831cb0ef41Sopenharmony_ci if (!first) 841cb0ef41Sopenharmony_ci json << ", "; 851cb0ef41Sopenharmony_ci first = false; 861cb0ef41Sopenharmony_ci json << MapToString(object); 871cb0ef41Sopenharmony_ci } 881cb0ef41Sopenharmony_ci json << "]\n\n"; 891cb0ef41Sopenharmony_ci return json.str(); 901cb0ef41Sopenharmony_ci} 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ciconst char* MatchPathSegment(const char* path, const char* expected) { 931cb0ef41Sopenharmony_ci size_t len = strlen(expected); 941cb0ef41Sopenharmony_ci if (StringEqualNoCaseN(path, expected, len)) { 951cb0ef41Sopenharmony_ci if (path[len] == '/') return path + len + 1; 961cb0ef41Sopenharmony_ci if (path[len] == '\0') return path + len; 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci return nullptr; 991cb0ef41Sopenharmony_ci} 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_civoid SendHttpResponse(InspectorSocket* socket, 1021cb0ef41Sopenharmony_ci const std::string& response, 1031cb0ef41Sopenharmony_ci int code) { 1041cb0ef41Sopenharmony_ci const char HEADERS[] = "HTTP/1.0 %d OK\r\n" 1051cb0ef41Sopenharmony_ci "Content-Type: application/json; charset=UTF-8\r\n" 1061cb0ef41Sopenharmony_ci "Cache-Control: no-cache\r\n" 1071cb0ef41Sopenharmony_ci "Content-Length: %zu\r\n" 1081cb0ef41Sopenharmony_ci "\r\n"; 1091cb0ef41Sopenharmony_ci char header[sizeof(HEADERS) + 20]; 1101cb0ef41Sopenharmony_ci int header_len = snprintf(header, 1111cb0ef41Sopenharmony_ci sizeof(header), 1121cb0ef41Sopenharmony_ci HEADERS, 1131cb0ef41Sopenharmony_ci code, 1141cb0ef41Sopenharmony_ci response.size()); 1151cb0ef41Sopenharmony_ci socket->Write(header, header_len); 1161cb0ef41Sopenharmony_ci socket->Write(response.data(), response.size()); 1171cb0ef41Sopenharmony_ci} 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_civoid SendVersionResponse(InspectorSocket* socket) { 1201cb0ef41Sopenharmony_ci std::map<std::string, std::string> response; 1211cb0ef41Sopenharmony_ci response["Browser"] = "node.js/" NODE_VERSION; 1221cb0ef41Sopenharmony_ci response["Protocol-Version"] = "1.1"; 1231cb0ef41Sopenharmony_ci SendHttpResponse(socket, MapToString(response), 200); 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_civoid SendHttpNotFound(InspectorSocket* socket) { 1271cb0ef41Sopenharmony_ci SendHttpResponse(socket, "", 404); 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_civoid SendProtocolJson(InspectorSocket* socket) { 1311cb0ef41Sopenharmony_ci z_stream strm; 1321cb0ef41Sopenharmony_ci strm.zalloc = Z_NULL; 1331cb0ef41Sopenharmony_ci strm.zfree = Z_NULL; 1341cb0ef41Sopenharmony_ci strm.opaque = Z_NULL; 1351cb0ef41Sopenharmony_ci CHECK_EQ(Z_OK, inflateInit(&strm)); 1361cb0ef41Sopenharmony_ci static const size_t kDecompressedSize = 1371cb0ef41Sopenharmony_ci PROTOCOL_JSON[0] * 0x10000u + 1381cb0ef41Sopenharmony_ci PROTOCOL_JSON[1] * 0x100u + 1391cb0ef41Sopenharmony_ci PROTOCOL_JSON[2]; 1401cb0ef41Sopenharmony_ci strm.next_in = const_cast<uint8_t*>(PROTOCOL_JSON + 3); 1411cb0ef41Sopenharmony_ci strm.avail_in = sizeof(PROTOCOL_JSON) - 3; 1421cb0ef41Sopenharmony_ci std::string data(kDecompressedSize, '\0'); 1431cb0ef41Sopenharmony_ci strm.next_out = reinterpret_cast<Byte*>(data.data()); 1441cb0ef41Sopenharmony_ci strm.avail_out = data.size(); 1451cb0ef41Sopenharmony_ci CHECK_EQ(Z_STREAM_END, inflate(&strm, Z_FINISH)); 1461cb0ef41Sopenharmony_ci CHECK_EQ(0, strm.avail_out); 1471cb0ef41Sopenharmony_ci CHECK_EQ(Z_OK, inflateEnd(&strm)); 1481cb0ef41Sopenharmony_ci SendHttpResponse(socket, data, 200); 1491cb0ef41Sopenharmony_ci} 1501cb0ef41Sopenharmony_ci} // namespace 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_cistd::string FormatWsAddress(const std::string& host, int port, 1531cb0ef41Sopenharmony_ci const std::string& target_id, 1541cb0ef41Sopenharmony_ci bool include_protocol) { 1551cb0ef41Sopenharmony_ci return FormatAddress(FormatHostPort(host, port), target_id, include_protocol); 1561cb0ef41Sopenharmony_ci} 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ciclass SocketSession { 1591cb0ef41Sopenharmony_ci public: 1601cb0ef41Sopenharmony_ci SocketSession(InspectorSocketServer* server, int id, int server_port); 1611cb0ef41Sopenharmony_ci void Close() { 1621cb0ef41Sopenharmony_ci ws_socket_.reset(); 1631cb0ef41Sopenharmony_ci } 1641cb0ef41Sopenharmony_ci void Send(const std::string& message); 1651cb0ef41Sopenharmony_ci void Own(InspectorSocket::Pointer ws_socket) { 1661cb0ef41Sopenharmony_ci ws_socket_ = std::move(ws_socket); 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci int id() const { return id_; } 1691cb0ef41Sopenharmony_ci int server_port() { 1701cb0ef41Sopenharmony_ci return server_port_; 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci InspectorSocket* ws_socket() { 1731cb0ef41Sopenharmony_ci return ws_socket_.get(); 1741cb0ef41Sopenharmony_ci } 1751cb0ef41Sopenharmony_ci void Accept(const std::string& ws_key) { 1761cb0ef41Sopenharmony_ci ws_socket_->AcceptUpgrade(ws_key); 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci void Decline() { 1791cb0ef41Sopenharmony_ci ws_socket_->CancelHandshake(); 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci class Delegate : public InspectorSocket::Delegate { 1831cb0ef41Sopenharmony_ci public: 1841cb0ef41Sopenharmony_ci Delegate(InspectorSocketServer* server, int session_id) 1851cb0ef41Sopenharmony_ci : server_(server), session_id_(session_id) { } 1861cb0ef41Sopenharmony_ci ~Delegate() override { 1871cb0ef41Sopenharmony_ci server_->SessionTerminated(session_id_); 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci void OnHttpGet(const std::string& host, const std::string& path) override; 1901cb0ef41Sopenharmony_ci void OnSocketUpgrade(const std::string& host, const std::string& path, 1911cb0ef41Sopenharmony_ci const std::string& ws_key) override; 1921cb0ef41Sopenharmony_ci void OnWsFrame(const std::vector<char>& data) override; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci private: 1951cb0ef41Sopenharmony_ci SocketSession* Session() { 1961cb0ef41Sopenharmony_ci return server_->Session(session_id_); 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci InspectorSocketServer* server_; 2001cb0ef41Sopenharmony_ci int session_id_; 2011cb0ef41Sopenharmony_ci }; 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci private: 2041cb0ef41Sopenharmony_ci const int id_; 2051cb0ef41Sopenharmony_ci InspectorSocket::Pointer ws_socket_; 2061cb0ef41Sopenharmony_ci const int server_port_; 2071cb0ef41Sopenharmony_ci}; 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ciclass ServerSocket { 2101cb0ef41Sopenharmony_ci public: 2111cb0ef41Sopenharmony_ci explicit ServerSocket(InspectorSocketServer* server) 2121cb0ef41Sopenharmony_ci : tcp_socket_(uv_tcp_t()), server_(server), unix_socket_(uv_pipe_t()) {} 2131cb0ef41Sopenharmony_ci int Listen(sockaddr* addr, uv_loop_t* loop, int pid = -1); 2141cb0ef41Sopenharmony_ci void Close() { 2151cb0ef41Sopenharmony_ci uv_close(reinterpret_cast<uv_handle_t*>(&tcp_socket_), FreeOnCloseCallback); 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci void CloseUnix() { 2181cb0ef41Sopenharmony_ci if (unix_socket_on) { 2191cb0ef41Sopenharmony_ci uv_close(reinterpret_cast<uv_handle_t*>(&unix_socket_), nullptr); 2201cb0ef41Sopenharmony_ci unix_socket_on = false; 2211cb0ef41Sopenharmony_ci } 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci int port() const { return port_; } 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci private: 2261cb0ef41Sopenharmony_ci template <typename UvHandle> 2271cb0ef41Sopenharmony_ci static ServerSocket* FromTcpSocket(UvHandle* socket) { 2281cb0ef41Sopenharmony_ci return node::ContainerOf(&ServerSocket::tcp_socket_, 2291cb0ef41Sopenharmony_ci reinterpret_cast<uv_tcp_t*>(socket)); 2301cb0ef41Sopenharmony_ci } 2311cb0ef41Sopenharmony_ci static void SocketConnectedCallback(uv_stream_t* tcp_socket, int status); 2321cb0ef41Sopenharmony_ci static void UnixSocketConnectedCallback(uv_stream_t* unix_socket, int status); 2331cb0ef41Sopenharmony_ci static void FreeOnCloseCallback(uv_handle_t* tcp_socket_) { 2341cb0ef41Sopenharmony_ci delete FromTcpSocket(tcp_socket_); 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci int DetectPort(uv_loop_t *loop, int pid); 2371cb0ef41Sopenharmony_ci ~ServerSocket() = default; 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci uv_tcp_t tcp_socket_; 2401cb0ef41Sopenharmony_ci InspectorSocketServer* server_; 2411cb0ef41Sopenharmony_ci uv_pipe_t unix_socket_; 2421cb0ef41Sopenharmony_ci int port_ = -1; 2431cb0ef41Sopenharmony_ci bool unix_socket_on = false; 2441cb0ef41Sopenharmony_ci}; 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_civoid PrintDebuggerReadyMessage( 2471cb0ef41Sopenharmony_ci const std::string& host, 2481cb0ef41Sopenharmony_ci const std::vector<InspectorSocketServer::ServerSocketPtr>& server_sockets, 2491cb0ef41Sopenharmony_ci const std::vector<std::string>& ids, 2501cb0ef41Sopenharmony_ci const char* verb, 2511cb0ef41Sopenharmony_ci bool publish_uid_stderr, 2521cb0ef41Sopenharmony_ci FILE* out) { 2531cb0ef41Sopenharmony_ci if (!publish_uid_stderr || out == nullptr) { 2541cb0ef41Sopenharmony_ci return; 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci for (const auto& server_socket : server_sockets) { 2571cb0ef41Sopenharmony_ci for (const std::string& id : ids) { 2581cb0ef41Sopenharmony_ci fprintf(out, "Debugger %s on %s\n", 2591cb0ef41Sopenharmony_ci verb, 2601cb0ef41Sopenharmony_ci FormatWsAddress(host, server_socket->port(), id, true).c_str()); 2611cb0ef41Sopenharmony_ci } 2621cb0ef41Sopenharmony_ci } 2631cb0ef41Sopenharmony_ci fprintf(out, "For help, see: %s\n", 2641cb0ef41Sopenharmony_ci "https://nodejs.org/en/docs/inspector"); 2651cb0ef41Sopenharmony_ci fflush(out); 2661cb0ef41Sopenharmony_ci} 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ciInspectorSocketServer::InspectorSocketServer( 2691cb0ef41Sopenharmony_ci std::unique_ptr<SocketServerDelegate> delegate, uv_loop_t* loop, 2701cb0ef41Sopenharmony_ci const std::string& host, int port, 2711cb0ef41Sopenharmony_ci const InspectPublishUid& inspect_publish_uid, FILE* out, int pid) 2721cb0ef41Sopenharmony_ci : loop_(loop), 2731cb0ef41Sopenharmony_ci delegate_(std::move(delegate)), 2741cb0ef41Sopenharmony_ci host_(host), 2751cb0ef41Sopenharmony_ci port_(port), 2761cb0ef41Sopenharmony_ci inspect_publish_uid_(inspect_publish_uid), 2771cb0ef41Sopenharmony_ci next_session_id_(0), 2781cb0ef41Sopenharmony_ci out_(out), 2791cb0ef41Sopenharmony_ci pid_(pid) { 2801cb0ef41Sopenharmony_ci delegate_->AssignServer(this); 2811cb0ef41Sopenharmony_ci state_ = ServerState::kNew; 2821cb0ef41Sopenharmony_ci} 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ciInspectorSocketServer::~InspectorSocketServer() = default; 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ciSocketSession* InspectorSocketServer::Session(int session_id) { 2871cb0ef41Sopenharmony_ci auto it = connected_sessions_.find(session_id); 2881cb0ef41Sopenharmony_ci return it == connected_sessions_.end() ? nullptr : it->second.second.get(); 2891cb0ef41Sopenharmony_ci} 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_civoid InspectorSocketServer::SessionStarted(int session_id, 2921cb0ef41Sopenharmony_ci const std::string& id, 2931cb0ef41Sopenharmony_ci const std::string& ws_key) { 2941cb0ef41Sopenharmony_ci SocketSession* session = Session(session_id); 2951cb0ef41Sopenharmony_ci if (!TargetExists(id)) { 2961cb0ef41Sopenharmony_ci session->Decline(); 2971cb0ef41Sopenharmony_ci return; 2981cb0ef41Sopenharmony_ci } 2991cb0ef41Sopenharmony_ci connected_sessions_[session_id].first = id; 3001cb0ef41Sopenharmony_ci session->Accept(ws_key); 3011cb0ef41Sopenharmony_ci delegate_->StartSession(session_id, id); 3021cb0ef41Sopenharmony_ci} 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_civoid InspectorSocketServer::SessionTerminated(int session_id) { 3051cb0ef41Sopenharmony_ci if (Session(session_id) == nullptr) { 3061cb0ef41Sopenharmony_ci return; 3071cb0ef41Sopenharmony_ci } 3081cb0ef41Sopenharmony_ci bool was_attached = connected_sessions_[session_id].first != ""; 3091cb0ef41Sopenharmony_ci if (was_attached) { 3101cb0ef41Sopenharmony_ci delegate_->EndSession(session_id); 3111cb0ef41Sopenharmony_ci } 3121cb0ef41Sopenharmony_ci connected_sessions_.erase(session_id); 3131cb0ef41Sopenharmony_ci if (connected_sessions_.empty()) { 3141cb0ef41Sopenharmony_ci if (was_attached && state_ == ServerState::kRunning 3151cb0ef41Sopenharmony_ci && !server_sockets_.empty()) { 3161cb0ef41Sopenharmony_ci PrintDebuggerReadyMessage(host_, 3171cb0ef41Sopenharmony_ci server_sockets_, 3181cb0ef41Sopenharmony_ci delegate_->GetTargetIds(), 3191cb0ef41Sopenharmony_ci "ending", 3201cb0ef41Sopenharmony_ci inspect_publish_uid_.console, 3211cb0ef41Sopenharmony_ci out_); 3221cb0ef41Sopenharmony_ci } 3231cb0ef41Sopenharmony_ci if (state_ == ServerState::kStopped) { 3241cb0ef41Sopenharmony_ci delegate_.reset(); 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci } 3271cb0ef41Sopenharmony_ci} 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_cibool InspectorSocketServer::HandleGetRequest(int session_id, 3301cb0ef41Sopenharmony_ci const std::string& host, 3311cb0ef41Sopenharmony_ci const std::string& path) { 3321cb0ef41Sopenharmony_ci SocketSession* session = Session(session_id); 3331cb0ef41Sopenharmony_ci InspectorSocket* socket = session->ws_socket(); 3341cb0ef41Sopenharmony_ci if (!inspect_publish_uid_.http) { 3351cb0ef41Sopenharmony_ci SendHttpNotFound(socket); 3361cb0ef41Sopenharmony_ci return true; 3371cb0ef41Sopenharmony_ci } 3381cb0ef41Sopenharmony_ci const char* command = MatchPathSegment(path.c_str(), "/json"); 3391cb0ef41Sopenharmony_ci if (command == nullptr) 3401cb0ef41Sopenharmony_ci return false; 3411cb0ef41Sopenharmony_ci 3421cb0ef41Sopenharmony_ci if (MatchPathSegment(command, "list") || command[0] == '\0') { 3431cb0ef41Sopenharmony_ci SendListResponse(socket, host, session); 3441cb0ef41Sopenharmony_ci return true; 3451cb0ef41Sopenharmony_ci } else if (MatchPathSegment(command, "protocol")) { 3461cb0ef41Sopenharmony_ci SendProtocolJson(socket); 3471cb0ef41Sopenharmony_ci return true; 3481cb0ef41Sopenharmony_ci } else if (MatchPathSegment(command, "version")) { 3491cb0ef41Sopenharmony_ci SendVersionResponse(socket); 3501cb0ef41Sopenharmony_ci return true; 3511cb0ef41Sopenharmony_ci } 3521cb0ef41Sopenharmony_ci return false; 3531cb0ef41Sopenharmony_ci} 3541cb0ef41Sopenharmony_ci 3551cb0ef41Sopenharmony_civoid InspectorSocketServer::SendListResponse(InspectorSocket* socket, 3561cb0ef41Sopenharmony_ci const std::string& host, 3571cb0ef41Sopenharmony_ci SocketSession* session) { 3581cb0ef41Sopenharmony_ci std::vector<std::map<std::string, std::string>> response; 3591cb0ef41Sopenharmony_ci for (const std::string& id : delegate_->GetTargetIds()) { 3601cb0ef41Sopenharmony_ci response.push_back(std::map<std::string, std::string>()); 3611cb0ef41Sopenharmony_ci std::map<std::string, std::string>& target_map = response.back(); 3621cb0ef41Sopenharmony_ci target_map["description"] = "node.js instance"; 3631cb0ef41Sopenharmony_ci target_map["faviconUrl"] = 3641cb0ef41Sopenharmony_ci "https://nodejs.org/static/images/favicons/favicon.ico"; 3651cb0ef41Sopenharmony_ci target_map["id"] = id; 3661cb0ef41Sopenharmony_ci target_map["title"] = delegate_->GetTargetTitle(id); 3671cb0ef41Sopenharmony_ci Escape(&target_map["title"]); 3681cb0ef41Sopenharmony_ci target_map["type"] = "node"; 3691cb0ef41Sopenharmony_ci // This attribute value is a "best effort" URL that is passed as a JSON 3701cb0ef41Sopenharmony_ci // string. It is not guaranteed to resolve to a valid resource. 3711cb0ef41Sopenharmony_ci target_map["url"] = delegate_->GetTargetUrl(id); 3721cb0ef41Sopenharmony_ci Escape(&target_map["url"]); 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci std::string detected_host = host; 3751cb0ef41Sopenharmony_ci if (detected_host.empty()) { 3761cb0ef41Sopenharmony_ci detected_host = FormatHostPort(socket->GetHost(), 3771cb0ef41Sopenharmony_ci session->server_port()); 3781cb0ef41Sopenharmony_ci } 3791cb0ef41Sopenharmony_ci std::string formatted_address = FormatAddress(detected_host, id, false); 3801cb0ef41Sopenharmony_ci target_map["devtoolsFrontendUrl"] = GetFrontendURL(false, 3811cb0ef41Sopenharmony_ci formatted_address); 3821cb0ef41Sopenharmony_ci // The compat URL is for Chrome browsers older than 66.0.3345.0 3831cb0ef41Sopenharmony_ci target_map["devtoolsFrontendUrlCompat"] = GetFrontendURL(true, 3841cb0ef41Sopenharmony_ci formatted_address); 3851cb0ef41Sopenharmony_ci target_map["webSocketDebuggerUrl"] = FormatAddress(detected_host, id, true); 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci SendHttpResponse(socket, MapsToString(response), 200); 3881cb0ef41Sopenharmony_ci} 3891cb0ef41Sopenharmony_ci 3901cb0ef41Sopenharmony_cistd::string InspectorSocketServer::GetFrontendURL(bool is_compat, 3911cb0ef41Sopenharmony_ci const std::string &formatted_address) { 3921cb0ef41Sopenharmony_ci std::ostringstream frontend_url; 3931cb0ef41Sopenharmony_ci frontend_url << "devtools://devtools/bundled/"; 3941cb0ef41Sopenharmony_ci frontend_url << (is_compat ? "inspector" : "js_app"); 3951cb0ef41Sopenharmony_ci frontend_url << ".html?v8only=true&ws="; 3961cb0ef41Sopenharmony_ci frontend_url << formatted_address; 3971cb0ef41Sopenharmony_ci return frontend_url.str(); 3981cb0ef41Sopenharmony_ci} 3991cb0ef41Sopenharmony_ci 4001cb0ef41Sopenharmony_cibool InspectorSocketServer::Start() { 4011cb0ef41Sopenharmony_ci CHECK_NOT_NULL(delegate_); 4021cb0ef41Sopenharmony_ci CHECK_EQ(state_, ServerState::kNew); 4031cb0ef41Sopenharmony_ci std::unique_ptr<SocketServerDelegate> delegate_holder; 4041cb0ef41Sopenharmony_ci // We will return it if startup is successful 4051cb0ef41Sopenharmony_ci delegate_.swap(delegate_holder); 4061cb0ef41Sopenharmony_ci struct addrinfo hints; 4071cb0ef41Sopenharmony_ci memset(&hints, 0, sizeof(hints)); 4081cb0ef41Sopenharmony_ci hints.ai_flags = AI_NUMERICSERV; 4091cb0ef41Sopenharmony_ci hints.ai_socktype = SOCK_STREAM; 4101cb0ef41Sopenharmony_ci uv_getaddrinfo_t req; 4111cb0ef41Sopenharmony_ci const std::string port_string = std::to_string(port_); 4121cb0ef41Sopenharmony_ci int err = uv_getaddrinfo(loop_, &req, nullptr, host_.c_str(), 4131cb0ef41Sopenharmony_ci port_string.c_str(), &hints); 4141cb0ef41Sopenharmony_ci if (err < 0) { 4151cb0ef41Sopenharmony_ci if (out_ != nullptr) { 4161cb0ef41Sopenharmony_ci fprintf(out_, "Unable to resolve \"%s\": %s\n", host_.c_str(), 4171cb0ef41Sopenharmony_ci uv_strerror(err)); 4181cb0ef41Sopenharmony_ci } 4191cb0ef41Sopenharmony_ci return false; 4201cb0ef41Sopenharmony_ci } 4211cb0ef41Sopenharmony_ci for (addrinfo* address = req.addrinfo; address != nullptr; 4221cb0ef41Sopenharmony_ci address = address->ai_next) { 4231cb0ef41Sopenharmony_ci auto server_socket = ServerSocketPtr(new ServerSocket(this)); 4241cb0ef41Sopenharmony_ci err = server_socket->Listen(address->ai_addr, loop_, pid_); 4251cb0ef41Sopenharmony_ci if (err == 0) 4261cb0ef41Sopenharmony_ci server_sockets_.push_back(std::move(server_socket)); 4271cb0ef41Sopenharmony_ci } 4281cb0ef41Sopenharmony_ci uv_freeaddrinfo(req.addrinfo); 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci // We only show error if we failed to start server on all addresses. We only 4311cb0ef41Sopenharmony_ci // show one error, for the last address. 4321cb0ef41Sopenharmony_ci if (server_sockets_.empty()) { 4331cb0ef41Sopenharmony_ci if (out_ != nullptr) { 4341cb0ef41Sopenharmony_ci fprintf(out_, "Starting inspector on %s:%d failed: %s\n", 4351cb0ef41Sopenharmony_ci host_.c_str(), port_, uv_strerror(err)); 4361cb0ef41Sopenharmony_ci fflush(out_); 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci return false; 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci delegate_.swap(delegate_holder); 4411cb0ef41Sopenharmony_ci state_ = ServerState::kRunning; 4421cb0ef41Sopenharmony_ci PrintDebuggerReadyMessage(host_, 4431cb0ef41Sopenharmony_ci server_sockets_, 4441cb0ef41Sopenharmony_ci delegate_->GetTargetIds(), 4451cb0ef41Sopenharmony_ci "listening", 4461cb0ef41Sopenharmony_ci inspect_publish_uid_.console, 4471cb0ef41Sopenharmony_ci out_); 4481cb0ef41Sopenharmony_ci return true; 4491cb0ef41Sopenharmony_ci} 4501cb0ef41Sopenharmony_ci 4511cb0ef41Sopenharmony_civoid InspectorSocketServer::Stop() { 4521cb0ef41Sopenharmony_ci if (state_ == ServerState::kStopped) 4531cb0ef41Sopenharmony_ci return; 4541cb0ef41Sopenharmony_ci CHECK_EQ(state_, ServerState::kRunning); 4551cb0ef41Sopenharmony_ci state_ = ServerState::kStopped; 4561cb0ef41Sopenharmony_ci server_sockets_.clear(); 4571cb0ef41Sopenharmony_ci if (done()) 4581cb0ef41Sopenharmony_ci delegate_.reset(); 4591cb0ef41Sopenharmony_ci} 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_civoid InspectorSocketServer::TerminateConnections() { 4621cb0ef41Sopenharmony_ci for (const auto& key_value : connected_sessions_) 4631cb0ef41Sopenharmony_ci key_value.second.second->Close(); 4641cb0ef41Sopenharmony_ci} 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_cibool InspectorSocketServer::TargetExists(const std::string& id) { 4671cb0ef41Sopenharmony_ci const std::vector<std::string>& target_ids = delegate_->GetTargetIds(); 4681cb0ef41Sopenharmony_ci const auto& found = std::find(target_ids.begin(), target_ids.end(), id); 4691cb0ef41Sopenharmony_ci return found != target_ids.end(); 4701cb0ef41Sopenharmony_ci} 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_ciint InspectorSocketServer::Port() const { 4731cb0ef41Sopenharmony_ci if (!server_sockets_.empty()) { 4741cb0ef41Sopenharmony_ci return server_sockets_[0]->port(); 4751cb0ef41Sopenharmony_ci } 4761cb0ef41Sopenharmony_ci return port_; 4771cb0ef41Sopenharmony_ci} 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_civoid InspectorSocketServer::Accept(int server_port, 4801cb0ef41Sopenharmony_ci uv_stream_t* server_socket) { 4811cb0ef41Sopenharmony_ci std::unique_ptr<SocketSession> session( 4821cb0ef41Sopenharmony_ci new SocketSession(this, next_session_id_++, server_port)); 4831cb0ef41Sopenharmony_ci 4841cb0ef41Sopenharmony_ci InspectorSocket::DelegatePointer delegate = 4851cb0ef41Sopenharmony_ci InspectorSocket::DelegatePointer( 4861cb0ef41Sopenharmony_ci new SocketSession::Delegate(this, session->id())); 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci InspectorSocket::Pointer inspector = 4891cb0ef41Sopenharmony_ci InspectorSocket::Accept(server_socket, std::move(delegate)); 4901cb0ef41Sopenharmony_ci if (inspector) { 4911cb0ef41Sopenharmony_ci session->Own(std::move(inspector)); 4921cb0ef41Sopenharmony_ci connected_sessions_[session->id()].second = std::move(session); 4931cb0ef41Sopenharmony_ci } 4941cb0ef41Sopenharmony_ci} 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_civoid InspectorSocketServer::Send(int session_id, const std::string& message) { 4971cb0ef41Sopenharmony_ci SocketSession* session = Session(session_id); 4981cb0ef41Sopenharmony_ci if (session != nullptr) { 4991cb0ef41Sopenharmony_ci session->Send(message); 5001cb0ef41Sopenharmony_ci } 5011cb0ef41Sopenharmony_ci} 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_civoid InspectorSocketServer::CloseServerSocket(ServerSocket* server) { 5041cb0ef41Sopenharmony_ci server->Close(); 5051cb0ef41Sopenharmony_ci server->CloseUnix(); 5061cb0ef41Sopenharmony_ci} 5071cb0ef41Sopenharmony_ci 5081cb0ef41Sopenharmony_ci// InspectorSession tracking 5091cb0ef41Sopenharmony_ciSocketSession::SocketSession(InspectorSocketServer* server, int id, 5101cb0ef41Sopenharmony_ci int server_port) 5111cb0ef41Sopenharmony_ci : id_(id), server_port_(server_port) {} 5121cb0ef41Sopenharmony_ci 5131cb0ef41Sopenharmony_civoid SocketSession::Send(const std::string& message) { 5141cb0ef41Sopenharmony_ci ws_socket_->Write(message.data(), message.length()); 5151cb0ef41Sopenharmony_ci} 5161cb0ef41Sopenharmony_ci 5171cb0ef41Sopenharmony_civoid SocketSession::Delegate::OnHttpGet(const std::string& host, 5181cb0ef41Sopenharmony_ci const std::string& path) { 5191cb0ef41Sopenharmony_ci if (!server_->HandleGetRequest(session_id_, host, path)) 5201cb0ef41Sopenharmony_ci Session()->ws_socket()->CancelHandshake(); 5211cb0ef41Sopenharmony_ci} 5221cb0ef41Sopenharmony_ci 5231cb0ef41Sopenharmony_civoid SocketSession::Delegate::OnSocketUpgrade(const std::string& host, 5241cb0ef41Sopenharmony_ci const std::string& path, 5251cb0ef41Sopenharmony_ci const std::string& ws_key) { 5261cb0ef41Sopenharmony_ci std::string id = path.empty() ? path : path.substr(1); 5271cb0ef41Sopenharmony_ci server_->SessionStarted(session_id_, id, ws_key); 5281cb0ef41Sopenharmony_ci} 5291cb0ef41Sopenharmony_ci 5301cb0ef41Sopenharmony_civoid SocketSession::Delegate::OnWsFrame(const std::vector<char>& data) { 5311cb0ef41Sopenharmony_ci server_->MessageReceived(session_id_, 5321cb0ef41Sopenharmony_ci std::string(data.data(), data.size())); 5331cb0ef41Sopenharmony_ci} 5341cb0ef41Sopenharmony_ci 5351cb0ef41Sopenharmony_ci// ServerSocket implementation 5361cb0ef41Sopenharmony_ciint ServerSocket::DetectPort(uv_loop_t *loop, int pid) { 5371cb0ef41Sopenharmony_ci sockaddr_storage addr; 5381cb0ef41Sopenharmony_ci int len = sizeof(addr); 5391cb0ef41Sopenharmony_ci int err = uv_tcp_getsockname(&tcp_socket_, 5401cb0ef41Sopenharmony_ci reinterpret_cast<struct sockaddr*>(&addr), &len); 5411cb0ef41Sopenharmony_ci if (err != 0) 5421cb0ef41Sopenharmony_ci return err; 5431cb0ef41Sopenharmony_ci int port; 5441cb0ef41Sopenharmony_ci if (addr.ss_family == AF_INET6) 5451cb0ef41Sopenharmony_ci port = reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port; 5461cb0ef41Sopenharmony_ci else 5471cb0ef41Sopenharmony_ci port = reinterpret_cast<const sockaddr_in*>(&addr)->sin_port; 5481cb0ef41Sopenharmony_ci port_ = ntohs(port); 5491cb0ef41Sopenharmony_ci if (!unix_socket_on && pid != -1) { 5501cb0ef41Sopenharmony_ci auto unixDomainSocketPath = "jsvm_devtools_remote_" + 5511cb0ef41Sopenharmony_ci std::to_string(port_) + "_" + std::to_string(pid); 5521cb0ef41Sopenharmony_ci auto *abstract = new char[unixDomainSocketPath.length() + 2]; 5531cb0ef41Sopenharmony_ci abstract[0] = '\0'; 5541cb0ef41Sopenharmony_ci strcpy(abstract + 1, unixDomainSocketPath.c_str()); 5551cb0ef41Sopenharmony_ci auto status = uv_pipe_init(loop, &unix_socket_, 0); 5561cb0ef41Sopenharmony_ci if (status == 0) { 5571cb0ef41Sopenharmony_ci status = uv_pipe_bind(&unix_socket_, abstract); 5581cb0ef41Sopenharmony_ci } 5591cb0ef41Sopenharmony_ci if (status == 0) { 5601cb0ef41Sopenharmony_ci constexpr int unixBacklog = 128; 5611cb0ef41Sopenharmony_ci status = uv_listen(reinterpret_cast<uv_stream_t*>(&unix_socket_), unixBacklog, 5621cb0ef41Sopenharmony_ci ServerSocket::UnixSocketConnectedCallback); 5631cb0ef41Sopenharmony_ci } 5641cb0ef41Sopenharmony_ci unix_socket_on = status == 0; 5651cb0ef41Sopenharmony_ci delete abstract; 5661cb0ef41Sopenharmony_ci } 5671cb0ef41Sopenharmony_ci return err; 5681cb0ef41Sopenharmony_ci} 5691cb0ef41Sopenharmony_ci 5701cb0ef41Sopenharmony_ciint ServerSocket::Listen(sockaddr* addr, uv_loop_t* loop, int pid) { 5711cb0ef41Sopenharmony_ci uv_tcp_t* server = &tcp_socket_; 5721cb0ef41Sopenharmony_ci CHECK_EQ(0, uv_tcp_init(loop, server)); 5731cb0ef41Sopenharmony_ci int err = uv_tcp_bind(server, addr, 0); 5741cb0ef41Sopenharmony_ci if (err == 0) { 5751cb0ef41Sopenharmony_ci // 511 is the value used by a 'net' module by default 5761cb0ef41Sopenharmony_ci err = uv_listen(reinterpret_cast<uv_stream_t*>(server), 511, 5771cb0ef41Sopenharmony_ci ServerSocket::SocketConnectedCallback); 5781cb0ef41Sopenharmony_ci } 5791cb0ef41Sopenharmony_ci if (err == 0) { 5801cb0ef41Sopenharmony_ci err = DetectPort(loop, pid); 5811cb0ef41Sopenharmony_ci } 5821cb0ef41Sopenharmony_ci return err; 5831cb0ef41Sopenharmony_ci} 5841cb0ef41Sopenharmony_ci 5851cb0ef41Sopenharmony_ci// static 5861cb0ef41Sopenharmony_civoid ServerSocket::SocketConnectedCallback(uv_stream_t* tcp_socket, 5871cb0ef41Sopenharmony_ci int status) { 5881cb0ef41Sopenharmony_ci if (status == 0) { 5891cb0ef41Sopenharmony_ci ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket); 5901cb0ef41Sopenharmony_ci // Memory is freed when the socket closes. 5911cb0ef41Sopenharmony_ci server_socket->server_->Accept(server_socket->port_, tcp_socket); 5921cb0ef41Sopenharmony_ci } 5931cb0ef41Sopenharmony_ci} 5941cb0ef41Sopenharmony_ci 5951cb0ef41Sopenharmony_civoid ServerSocket::UnixSocketConnectedCallback(uv_stream_t* unix_socket, 5961cb0ef41Sopenharmony_ci int status) { 5971cb0ef41Sopenharmony_ci if (status == 0) { 5981cb0ef41Sopenharmony_ci (void)unix_socket; 5991cb0ef41Sopenharmony_ci } 6001cb0ef41Sopenharmony_ci} 6011cb0ef41Sopenharmony_ci} // namespace inspector 6021cb0ef41Sopenharmony_ci} // namespace node 603