GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/inspector_socket_server.cc Lines: 0 287 0.0 %
Date: 2019-02-01 22:03:38 Branches: 0 128 0.0 %

Line Branch Exec Source
1
#include "inspector_socket_server.h"
2
3
#include "node.h"
4
#include "uv.h"
5
#include "zlib.h"
6
7
#include <algorithm>
8
#include <map>
9
#include <set>
10
#include <sstream>
11
12
namespace node {
13
namespace inspector {
14
15
// Function is declared in inspector_io.h so the rest of the node does not
16
// depend on inspector_socket_server.h
17
std::string FormatWsAddress(const std::string& host, int port,
18
                            const std::string& target_id,
19
                            bool include_protocol);
20
namespace {
21
22
static const uint8_t PROTOCOL_JSON[] = {
23
  #include "v8_inspector_protocol_json.h"  // NOLINT(build/include_order)
24
};
25
26
void Escape(std::string* string) {
27
  for (char& c : *string) {
28
    c = (c == '\"' || c == '\\') ? '_' : c;
29
  }
30
}
31
32
std::string FormatHostPort(const std::string& host, int port) {
33
  // Host is valid (socket was bound) so colon means it's a v6 IP address
34
  bool v6 = host.find(':') != std::string::npos;
35
  std::ostringstream url;
36
  if (v6) {
37
    url << '[';
38
  }
39
  url << host;
40
  if (v6) {
41
    url << ']';
42
  }
43
  url << ':' << port;
44
  return url.str();
45
}
46
47
std::string FormatAddress(const std::string& host,
48
                          const std::string& target_id,
49
                          bool include_protocol) {
50
  std::ostringstream url;
51
  if (include_protocol)
52
    url << "ws://";
53
  url << host << '/' << target_id;
54
  return url.str();
55
}
56
57
std::string MapToString(const std::map<std::string, std::string>& object) {
58
  bool first = true;
59
  std::ostringstream json;
60
  json << "{\n";
61
  for (const auto& name_value : object) {
62
    if (!first)
63
      json << ",\n";
64
    first = false;
65
    json << "  \"" << name_value.first << "\": \"";
66
    json << name_value.second << "\"";
67
  }
68
  json << "\n} ";
69
  return json.str();
70
}
71
72
std::string MapsToString(
73
    const std::vector<std::map<std::string, std::string>>& array) {
74
  bool first = true;
75
  std::ostringstream json;
76
  json << "[ ";
77
  for (const auto& object : array) {
78
    if (!first)
79
      json << ", ";
80
    first = false;
81
    json << MapToString(object);
82
  }
83
  json << "]\n\n";
84
  return json.str();
85
}
86
87
const char* MatchPathSegment(const char* path, const char* expected) {
88
  size_t len = strlen(expected);
89
  if (StringEqualNoCaseN(path, expected, len)) {
90
    if (path[len] == '/') return path + len + 1;
91
    if (path[len] == '\0') return path + len;
92
  }
93
  return nullptr;
94
}
95
96
void PrintDebuggerReadyMessage(const std::string& host,
97
                               int port,
98
                               const std::vector<std::string>& ids,
99
                               FILE* out) {
100
  if (out == nullptr) {
101
    return;
102
  }
103
  for (const std::string& id : ids) {
104
    fprintf(out, "Debugger listening on %s\n",
105
            FormatWsAddress(host, port, id, true).c_str());
106
  }
107
  fprintf(out, "For help, see: %s\n",
108
          "https://nodejs.org/en/docs/inspector");
109
  fflush(out);
110
}
111
112
void SendHttpResponse(InspectorSocket* socket, const std::string& response) {
113
  const char HEADERS[] = "HTTP/1.0 200 OK\r\n"
114
                         "Content-Type: application/json; charset=UTF-8\r\n"
115
                         "Cache-Control: no-cache\r\n"
116
                         "Content-Length: %zu\r\n"
117
                         "\r\n";
118
  char header[sizeof(HEADERS) + 20];
119
  int header_len = snprintf(header, sizeof(header), HEADERS, response.size());
120
  socket->Write(header, header_len);
121
  socket->Write(response.data(), response.size());
122
}
123
124
void SendVersionResponse(InspectorSocket* socket) {
125
  std::map<std::string, std::string> response;
126
  response["Browser"] = "node.js/" NODE_VERSION;
127
  response["Protocol-Version"] = "1.1";
128
  SendHttpResponse(socket, MapToString(response));
129
}
130
131
void SendProtocolJson(InspectorSocket* socket) {
132
  z_stream strm;
133
  strm.zalloc = Z_NULL;
134
  strm.zfree = Z_NULL;
135
  strm.opaque = Z_NULL;
136
  CHECK_EQ(Z_OK, inflateInit(&strm));
137
  static const size_t kDecompressedSize =
138
      PROTOCOL_JSON[0] * 0x10000u +
139
      PROTOCOL_JSON[1] * 0x100u +
140
      PROTOCOL_JSON[2];
141
  strm.next_in = const_cast<uint8_t*>(PROTOCOL_JSON + 3);
142
  strm.avail_in = sizeof(PROTOCOL_JSON) - 3;
143
  std::string data(kDecompressedSize, '\0');
144
  strm.next_out = reinterpret_cast<Byte*>(&data[0]);
145
  strm.avail_out = data.size();
146
  CHECK_EQ(Z_STREAM_END, inflate(&strm, Z_FINISH));
147
  CHECK_EQ(0, strm.avail_out);
148
  CHECK_EQ(Z_OK, inflateEnd(&strm));
149
  SendHttpResponse(socket, data);
150
}
151
}  // namespace
152
153
std::string FormatWsAddress(const std::string& host, int port,
154
                            const std::string& target_id,
155
                            bool include_protocol) {
156
  return FormatAddress(FormatHostPort(host, port), target_id, include_protocol);
157
}
158
159
class SocketSession {
160
 public:
161
  SocketSession(InspectorSocketServer* server, int id, int server_port);
162
  void Close() {
163
    ws_socket_.reset();
164
  }
165
  void Send(const std::string& message);
166
  void Own(InspectorSocket::Pointer ws_socket) {
167
    ws_socket_ = std::move(ws_socket);
168
  }
169
  int id() const { return id_; }
170
  int server_port() {
171
    return server_port_;
172
  }
173
  InspectorSocket* ws_socket() {
174
    return ws_socket_.get();
175
  }
176
  void Accept(const std::string& ws_key) {
177
    ws_socket_->AcceptUpgrade(ws_key);
178
  }
179
  void Decline() {
180
    ws_socket_->CancelHandshake();
181
  }
182
183
  class Delegate : public InspectorSocket::Delegate {
184
   public:
185
    Delegate(InspectorSocketServer* server, int session_id)
186
             : server_(server), session_id_(session_id) { }
187
    ~Delegate() {
188
      server_->SessionTerminated(session_id_);
189
    }
190
    void OnHttpGet(const std::string& host, const std::string& path) override;
191
    void OnSocketUpgrade(const std::string& host, const std::string& path,
192
                         const std::string& ws_key) override;
193
    void OnWsFrame(const std::vector<char>& data) override;
194
195
   private:
196
    SocketSession* Session() {
197
      return server_->Session(session_id_);
198
    }
199
200
    InspectorSocketServer* server_;
201
    int session_id_;
202
  };
203
204
 private:
205
  const int id_;
206
  InspectorSocket::Pointer ws_socket_;
207
  const int server_port_;
208
};
209
210
class ServerSocket {
211
 public:
212
  explicit ServerSocket(InspectorSocketServer* server)
213
                        : tcp_socket_(uv_tcp_t()), server_(server) {}
214
  int Listen(sockaddr* addr, uv_loop_t* loop);
215
  void Close() {
216
    uv_close(reinterpret_cast<uv_handle_t*>(&tcp_socket_), FreeOnCloseCallback);
217
  }
218
  int port() const { return port_; }
219
220
 private:
221
  template <typename UvHandle>
222
  static ServerSocket* FromTcpSocket(UvHandle* socket) {
223
    return node::ContainerOf(&ServerSocket::tcp_socket_,
224
                             reinterpret_cast<uv_tcp_t*>(socket));
225
  }
226
  static void SocketConnectedCallback(uv_stream_t* tcp_socket, int status);
227
  static void FreeOnCloseCallback(uv_handle_t* tcp_socket_) {
228
    delete FromTcpSocket(tcp_socket_);
229
  }
230
  int DetectPort();
231
  ~ServerSocket() = default;
232
233
  uv_tcp_t tcp_socket_;
234
  InspectorSocketServer* server_;
235
  int port_ = -1;
236
};
237
238
InspectorSocketServer::InspectorSocketServer(
239
    std::unique_ptr<SocketServerDelegate> delegate, uv_loop_t* loop,
240
    const std::string& host, int port, FILE* out)
241
    : loop_(loop), delegate_(std::move(delegate)), host_(host), port_(port),
242
      next_session_id_(0), out_(out) {
243
  delegate_->AssignServer(this);
244
  state_ = ServerState::kNew;
245
}
246
247
InspectorSocketServer::~InspectorSocketServer() = default;
248
249
SocketSession* InspectorSocketServer::Session(int session_id) {
250
  auto it = connected_sessions_.find(session_id);
251
  return it == connected_sessions_.end() ? nullptr : it->second.second.get();
252
}
253
254
void InspectorSocketServer::SessionStarted(int session_id,
255
                                           const std::string& id,
256
                                           const std::string& ws_key) {
257
  SocketSession* session = Session(session_id);
258
  if (!TargetExists(id)) {
259
    session->Decline();
260
    return;
261
  }
262
  connected_sessions_[session_id].first = id;
263
  session->Accept(ws_key);
264
  delegate_->StartSession(session_id, id);
265
}
266
267
void InspectorSocketServer::SessionTerminated(int session_id) {
268
  if (Session(session_id) == nullptr) {
269
    return;
270
  }
271
  bool was_attached = connected_sessions_[session_id].first != "";
272
  if (was_attached) {
273
    delegate_->EndSession(session_id);
274
  }
275
  connected_sessions_.erase(session_id);
276
  if (connected_sessions_.empty()) {
277
    if (was_attached && state_ == ServerState::kRunning
278
        && !server_sockets_.empty()) {
279
      PrintDebuggerReadyMessage(host_, server_sockets_[0]->port(),
280
                                delegate_->GetTargetIds(), out_);
281
    }
282
    if (state_ == ServerState::kStopped) {
283
      delegate_.reset();
284
    }
285
  }
286
}
287
288
bool InspectorSocketServer::HandleGetRequest(int session_id,
289
                                             const std::string& host,
290
                                             const std::string& path) {
291
  SocketSession* session = Session(session_id);
292
  InspectorSocket* socket = session->ws_socket();
293
  const char* command = MatchPathSegment(path.c_str(), "/json");
294
  if (command == nullptr)
295
    return false;
296
297
  if (MatchPathSegment(command, "list") || command[0] == '\0') {
298
    SendListResponse(socket, host, session);
299
    return true;
300
  } else if (MatchPathSegment(command, "protocol")) {
301
    SendProtocolJson(socket);
302
    return true;
303
  } else if (MatchPathSegment(command, "version")) {
304
    SendVersionResponse(socket);
305
    return true;
306
  }
307
  return false;
308
}
309
310
void InspectorSocketServer::SendListResponse(InspectorSocket* socket,
311
                                             const std::string& host,
312
                                             SocketSession* session) {
313
  std::vector<std::map<std::string, std::string>> response;
314
  for (const std::string& id : delegate_->GetTargetIds()) {
315
    response.push_back(std::map<std::string, std::string>());
316
    std::map<std::string, std::string>& target_map = response.back();
317
    target_map["description"] = "node.js instance";
318
    target_map["faviconUrl"] = "https://nodejs.org/static/favicon.ico";
319
    target_map["id"] = id;
320
    target_map["title"] = delegate_->GetTargetTitle(id);
321
    Escape(&target_map["title"]);
322
    target_map["type"] = "node";
323
    // This attribute value is a "best effort" URL that is passed as a JSON
324
    // string. It is not guaranteed to resolve to a valid resource.
325
    target_map["url"] = delegate_->GetTargetUrl(id);
326
    Escape(&target_map["url"]);
327
328
    std::string detected_host = host;
329
    if (detected_host.empty()) {
330
      detected_host = FormatHostPort(socket->GetHost(),
331
                                     session->server_port());
332
    }
333
    std::string formatted_address = FormatAddress(detected_host, id, false);
334
    target_map["devtoolsFrontendUrl"] = GetFrontendURL(false,
335
                                                       formatted_address);
336
    // The compat URL is for Chrome browsers older than 66.0.3345.0
337
    target_map["devtoolsFrontendUrlCompat"] = GetFrontendURL(true,
338
                                                             formatted_address);
339
    target_map["webSocketDebuggerUrl"] = FormatAddress(detected_host, id, true);
340
  }
341
  SendHttpResponse(socket, MapsToString(response));
342
}
343
344
std::string InspectorSocketServer::GetFrontendURL(bool is_compat,
345
    const std::string &formatted_address) {
346
  std::ostringstream frontend_url;
347
  frontend_url << "chrome-devtools://devtools/bundled/";
348
  frontend_url << (is_compat ? "inspector" : "js_app");
349
  frontend_url << ".html?experiments=true&v8only=true&ws=";
350
  frontend_url << formatted_address;
351
  return frontend_url.str();
352
}
353
354
bool InspectorSocketServer::Start() {
355
  CHECK_NE(delegate_, nullptr);
356
  CHECK_EQ(state_, ServerState::kNew);
357
  std::unique_ptr<SocketServerDelegate> delegate_holder;
358
  // We will return it if startup is successful
359
  delegate_.swap(delegate_holder);
360
  struct addrinfo hints;
361
  memset(&hints, 0, sizeof(hints));
362
  hints.ai_flags = AI_NUMERICSERV;
363
  hints.ai_socktype = SOCK_STREAM;
364
  uv_getaddrinfo_t req;
365
  const std::string port_string = std::to_string(port_);
366
  int err = uv_getaddrinfo(loop_, &req, nullptr, host_.c_str(),
367
                           port_string.c_str(), &hints);
368
  if (err < 0) {
369
    if (out_ != nullptr) {
370
      fprintf(out_, "Unable to resolve \"%s\": %s\n", host_.c_str(),
371
              uv_strerror(err));
372
    }
373
    return false;
374
  }
375
  for (addrinfo* address = req.addrinfo; address != nullptr;
376
       address = address->ai_next) {
377
    auto server_socket = ServerSocketPtr(new ServerSocket(this));
378
    err = server_socket->Listen(address->ai_addr, loop_);
379
    if (err == 0)
380
      server_sockets_.push_back(std::move(server_socket));
381
  }
382
  uv_freeaddrinfo(req.addrinfo);
383
384
  // We only show error if we failed to start server on all addresses. We only
385
  // show one error, for the last address.
386
  if (server_sockets_.empty()) {
387
    if (out_ != nullptr) {
388
      fprintf(out_, "Starting inspector on %s:%d failed: %s\n",
389
              host_.c_str(), port_, uv_strerror(err));
390
      fflush(out_);
391
    }
392
    return false;
393
  }
394
  delegate_.swap(delegate_holder);
395
  state_ = ServerState::kRunning;
396
  // getaddrinfo sorts the addresses, so the first port is most relevant.
397
  PrintDebuggerReadyMessage(host_, server_sockets_[0]->port(),
398
                            delegate_->GetTargetIds(), out_);
399
  return true;
400
}
401
402
void InspectorSocketServer::Stop() {
403
  if (state_ == ServerState::kStopped)
404
    return;
405
  CHECK_EQ(state_, ServerState::kRunning);
406
  state_ = ServerState::kStopped;
407
  server_sockets_.clear();
408
  if (done())
409
    delegate_.reset();
410
}
411
412
void InspectorSocketServer::TerminateConnections() {
413
  for (const auto& key_value : connected_sessions_)
414
    key_value.second.second->Close();
415
}
416
417
bool InspectorSocketServer::TargetExists(const std::string& id) {
418
  const std::vector<std::string>& target_ids = delegate_->GetTargetIds();
419
  const auto& found = std::find(target_ids.begin(), target_ids.end(), id);
420
  return found != target_ids.end();
421
}
422
423
int InspectorSocketServer::Port() const {
424
  if (!server_sockets_.empty()) {
425
    return server_sockets_[0]->port();
426
  }
427
  return port_;
428
}
429
430
void InspectorSocketServer::Accept(int server_port,
431
                                   uv_stream_t* server_socket) {
432
  std::unique_ptr<SocketSession> session(
433
      new SocketSession(this, next_session_id_++, server_port));
434
435
  InspectorSocket::DelegatePointer delegate =
436
      InspectorSocket::DelegatePointer(
437
          new SocketSession::Delegate(this, session->id()));
438
439
  InspectorSocket::Pointer inspector =
440
      InspectorSocket::Accept(server_socket, std::move(delegate));
441
  if (inspector) {
442
    session->Own(std::move(inspector));
443
    connected_sessions_[session->id()].second = std::move(session);
444
  }
445
}
446
447
void InspectorSocketServer::Send(int session_id, const std::string& message) {
448
  SocketSession* session = Session(session_id);
449
  if (session != nullptr) {
450
    session->Send(message);
451
  }
452
}
453
454
void InspectorSocketServer::CloseServerSocket(ServerSocket* server) {
455
  server->Close();
456
}
457
458
// InspectorSession tracking
459
SocketSession::SocketSession(InspectorSocketServer* server, int id,
460
                             int server_port)
461
    : id_(id), server_port_(server_port) {}
462
463
void SocketSession::Send(const std::string& message) {
464
  ws_socket_->Write(message.data(), message.length());
465
}
466
467
void SocketSession::Delegate::OnHttpGet(const std::string& host,
468
                                        const std::string& path) {
469
  if (!server_->HandleGetRequest(session_id_, host, path))
470
    Session()->ws_socket()->CancelHandshake();
471
}
472
473
void SocketSession::Delegate::OnSocketUpgrade(const std::string& host,
474
                                              const std::string& path,
475
                                              const std::string& ws_key) {
476
  std::string id = path.empty() ? path : path.substr(1);
477
  server_->SessionStarted(session_id_, id, ws_key);
478
}
479
480
void SocketSession::Delegate::OnWsFrame(const std::vector<char>& data) {
481
  server_->MessageReceived(session_id_,
482
                           std::string(data.data(), data.size()));
483
}
484
485
// ServerSocket implementation
486
int ServerSocket::DetectPort() {
487
  sockaddr_storage addr;
488
  int len = sizeof(addr);
489
  int err = uv_tcp_getsockname(&tcp_socket_,
490
                               reinterpret_cast<struct sockaddr*>(&addr), &len);
491
  if (err != 0)
492
    return err;
493
  int port;
494
  if (addr.ss_family == AF_INET6)
495
    port = reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port;
496
  else
497
    port = reinterpret_cast<const sockaddr_in*>(&addr)->sin_port;
498
  port_ = ntohs(port);
499
  return err;
500
}
501
502
int ServerSocket::Listen(sockaddr* addr, uv_loop_t* loop) {
503
  uv_tcp_t* server = &tcp_socket_;
504
  CHECK_EQ(0, uv_tcp_init(loop, server));
505
  int err = uv_tcp_bind(server, addr, 0);
506
  if (err == 0) {
507
    // 511 is the value used by a 'net' module by default
508
    err = uv_listen(reinterpret_cast<uv_stream_t*>(server), 511,
509
                    ServerSocket::SocketConnectedCallback);
510
  }
511
  if (err == 0) {
512
    err = DetectPort();
513
  }
514
  return err;
515
}
516
517
// static
518
void ServerSocket::SocketConnectedCallback(uv_stream_t* tcp_socket,
519
                                           int status) {
520
  if (status == 0) {
521
    ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket);
522
    // Memory is freed when the socket closes.
523
    server_socket->server_->Accept(server_socket->port_, tcp_socket);
524
  }
525
}
526
}  // namespace inspector
527
}  // namespace node