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: 299 328 91.2 %
Date: 2020-07-19 22:14:24 Branches: 97 128 75.8 %

Line Branch Exec Source
1
#include "inspector_socket_server.h"
2
3
#include "node.h"
4
#include "util-inl.h"
5
#include "uv.h"
6
#include "zlib.h"
7
8
#include <algorithm>
9
#include <map>
10
#include <set>
11
#include <sstream>
12
13
namespace node {
14
namespace inspector {
15
16
// Function is declared in inspector_io.h so the rest of the node does not
17
// depend on inspector_socket_server.h
18
std::string FormatWsAddress(const std::string& host, int port,
19
                            const std::string& target_id,
20
                            bool include_protocol);
21
namespace {
22
23
static const uint8_t PROTOCOL_JSON[] = {
24
  #include "v8_inspector_protocol_json.h"  // NOLINT(build/include_order)
25
};
26
27
42
void Escape(std::string* string) {
28
3455
  for (char& c : *string) {
29

3413
    c = (c == '\"' || c == '\\') ? '_' : c;
30
  }
31
42
}
32
33
83
std::string FormatHostPort(const std::string& host, int port) {
34
  // Host is valid (socket was bound) so colon means it's a v6 IP address
35
83
  bool v6 = host.find(':') != std::string::npos;
36
166
  std::ostringstream url;
37
83
  if (v6) {
38
4
    url << '[';
39
  }
40
83
  url << host;
41
83
  if (v6) {
42
4
    url << ']';
43
  }
44
83
  url << ':' << port;
45
166
  return url.str();
46
}
47
48
125
std::string FormatAddress(const std::string& host,
49
                          const std::string& target_id,
50
                          bool include_protocol) {
51
250
  std::ostringstream url;
52
125
  if (include_protocol)
53
104
    url << "ws://";
54
125
  url << host << '/' << target_id;
55
250
  return url.str();
56
}
57
58
22
std::string MapToString(const std::map<std::string, std::string>& object) {
59
22
  bool first = true;
60
44
  std::ostringstream json;
61
22
  json << "{\n";
62
213
  for (const auto& name_value : object) {
63
191
    if (!first)
64
169
      json << ",\n";
65
191
    first = false;
66
191
    json << "  \"" << name_value.first << "\": \"";
67
191
    json << name_value.second << "\"";
68
  }
69
22
  json << "\n} ";
70
44
  return json.str();
71
}
72
73
27
std::string MapsToString(
74
    const std::vector<std::map<std::string, std::string>>& array) {
75
27
  bool first = true;
76
54
  std::ostringstream json;
77
27
  json << "[ ";
78
48
  for (const auto& object : array) {
79
21
    if (!first)
80
      json << ", ";
81
21
    first = false;
82
21
    json << MapToString(object);
83
  }
84
27
  json << "]\n\n";
85
54
  return json.str();
86
}
87
88
70
const char* MatchPathSegment(const char* path, const char* expected) {
89
70
  size_t len = strlen(expected);
90
70
  if (StringEqualNoCaseN(path, expected, len)) {
91
57
    if (path[len] == '/') return path + len + 1;
92
28
    if (path[len] == '\0') return path + len;
93
  }
94
13
  return nullptr;
95
}
96
97
29
void SendHttpResponse(InspectorSocket* socket,
98
                      const std::string& response,
99
                      int code) {
100
  const char HEADERS[] = "HTTP/1.0 %d OK\r\n"
101
                         "Content-Type: application/json; charset=UTF-8\r\n"
102
                         "Cache-Control: no-cache\r\n"
103
                         "Content-Length: %zu\r\n"
104
29
                         "\r\n";
105
  char header[sizeof(HEADERS) + 20];
106
29
  int header_len = snprintf(header,
107
                            sizeof(header),
108
                            HEADERS,
109
                            code,
110
29
                            response.size());
111
29
  socket->Write(header, header_len);
112
29
  socket->Write(response.data(), response.size());
113
29
}
114
115
1
void SendVersionResponse(InspectorSocket* socket) {
116
2
  std::map<std::string, std::string> response;
117
1
  response["Browser"] = "node.js/" NODE_VERSION;
118
1
  response["Protocol-Version"] = "1.1";
119
1
  SendHttpResponse(socket, MapToString(response), 200);
120
1
}
121
122
1
void SendHttpNotFound(InspectorSocket* socket) {
123
1
  SendHttpResponse(socket, "", 404);
124
1
}
125
126
void SendProtocolJson(InspectorSocket* socket) {
127
  z_stream strm;
128
  strm.zalloc = Z_NULL;
129
  strm.zfree = Z_NULL;
130
  strm.opaque = Z_NULL;
131
  CHECK_EQ(Z_OK, inflateInit(&strm));
132
  static const size_t kDecompressedSize =
133
      PROTOCOL_JSON[0] * 0x10000u +
134
      PROTOCOL_JSON[1] * 0x100u +
135
      PROTOCOL_JSON[2];
136
  strm.next_in = const_cast<uint8_t*>(PROTOCOL_JSON + 3);
137
  strm.avail_in = sizeof(PROTOCOL_JSON) - 3;
138
  std::string data(kDecompressedSize, '\0');
139
  strm.next_out = reinterpret_cast<Byte*>(&data[0]);
140
  strm.avail_out = data.size();
141
  CHECK_EQ(Z_STREAM_END, inflate(&strm, Z_FINISH));
142
  CHECK_EQ(0, strm.avail_out);
143
  CHECK_EQ(Z_OK, inflateEnd(&strm));
144
  SendHttpResponse(socket, data, 200);
145
}
146
}  // namespace
147
148
83
std::string FormatWsAddress(const std::string& host, int port,
149
                            const std::string& target_id,
150
                            bool include_protocol) {
151
83
  return FormatAddress(FormatHostPort(host, port), target_id, include_protocol);
152
}
153
154
55
class SocketSession {
155
 public:
156
  SocketSession(InspectorSocketServer* server, int id, int server_port);
157
3
  void Close() {
158
3
    ws_socket_.reset();
159
3
  }
160
  void Send(const std::string& message);
161
55
  void Own(InspectorSocket::Pointer ws_socket) {
162
55
    ws_socket_ = std::move(ws_socket);
163
55
  }
164
110
  int id() const { return id_; }
165
  int server_port() {
166
    return server_port_;
167
  }
168
35
  InspectorSocket* ws_socket() {
169
35
    return ws_socket_.get();
170
  }
171
23
  void Accept(const std::string& ws_key) {
172
23
    ws_socket_->AcceptUpgrade(ws_key);
173
23
  }
174
1
  void Decline() {
175
1
    ws_socket_->CancelHandshake();
176
1
  }
177
178
  class Delegate : public InspectorSocket::Delegate {
179
   public:
180
55
    Delegate(InspectorSocketServer* server, int session_id)
181
55
             : server_(server), session_id_(session_id) { }
182
165
    ~Delegate() override {
183
55
      server_->SessionTerminated(session_id_);
184
110
    }
185
    void OnHttpGet(const std::string& host, const std::string& path) override;
186
    void OnSocketUpgrade(const std::string& host, const std::string& path,
187
                         const std::string& ws_key) override;
188
    void OnWsFrame(const std::vector<char>& data) override;
189
190
   private:
191
3
    SocketSession* Session() {
192
3
      return server_->Session(session_id_);
193
    }
194
195
    InspectorSocketServer* server_;
196
    int session_id_;
197
  };
198
199
 private:
200
  const int id_;
201
  InspectorSocket::Pointer ws_socket_;
202
  const int server_port_;
203
};
204
205
class ServerSocket {
206
 public:
207
94
  explicit ServerSocket(InspectorSocketServer* server)
208
94
                        : tcp_socket_(uv_tcp_t()), server_(server) {}
209
  int Listen(sockaddr* addr, uv_loop_t* loop);
210
94
  void Close() {
211
94
    uv_close(reinterpret_cast<uv_handle_t*>(&tcp_socket_), FreeOnCloseCallback);
212
94
  }
213
168
  int port() const { return port_; }
214
215
 private:
216
  template <typename UvHandle>
217
149
  static ServerSocket* FromTcpSocket(UvHandle* socket) {
218
298
    return node::ContainerOf(&ServerSocket::tcp_socket_,
219
298
                             reinterpret_cast<uv_tcp_t*>(socket));
220
  }
221
  static void SocketConnectedCallback(uv_stream_t* tcp_socket, int status);
222
94
  static void FreeOnCloseCallback(uv_handle_t* tcp_socket_) {
223
94
    delete FromTcpSocket(tcp_socket_);
224
94
  }
225
  int DetectPort();
226
  ~ServerSocket() = default;
227
228
  uv_tcp_t tcp_socket_;
229
  InspectorSocketServer* server_;
230
  int port_ = -1;
231
};
232
233
88
void PrintDebuggerReadyMessage(
234
    const std::string& host,
235
    const std::vector<InspectorSocketServer::ServerSocketPtr>& server_sockets,
236
    const std::vector<std::string>& ids,
237
    bool publish_uid_stderr,
238
    FILE* out) {
239

88
  if (!publish_uid_stderr || out == nullptr) {
240
12
    return;
241
  }
242
154
  for (const auto& server_socket : server_sockets) {
243
156
    for (const std::string& id : ids) {
244
78
      fprintf(out, "Debugger listening on %s\n",
245
156
              FormatWsAddress(host, server_socket->port(), id, true).c_str());
246
    }
247
  }
248
  fprintf(out, "For help, see: %s\n",
249
76
          "https://nodejs.org/en/docs/inspector");
250
76
  fflush(out);
251
}
252
253
89
InspectorSocketServer::InspectorSocketServer(
254
    std::unique_ptr<SocketServerDelegate> delegate, uv_loop_t* loop,
255
    const std::string& host, int port,
256
89
    const InspectPublishUid& inspect_publish_uid, FILE* out)
257
    : loop_(loop),
258
89
      delegate_(std::move(delegate)),
259
      host_(host),
260
      port_(port),
261
      inspect_publish_uid_(inspect_publish_uid),
262
      next_session_id_(0),
263
178
      out_(out) {
264
89
  delegate_->AssignServer(this);
265
89
  state_ = ServerState::kNew;
266
89
}
267
268
InspectorSocketServer::~InspectorSocketServer() = default;
269
270
1354
SocketSession* InspectorSocketServer::Session(int session_id) {
271
1354
  auto it = connected_sessions_.find(session_id);
272
1354
  return it == connected_sessions_.end() ? nullptr : it->second.second.get();
273
}
274
275
24
void InspectorSocketServer::SessionStarted(int session_id,
276
                                           const std::string& id,
277
                                           const std::string& ws_key) {
278
24
  SocketSession* session = Session(session_id);
279
24
  if (!TargetExists(id)) {
280
1
    session->Decline();
281
1
    return;
282
  }
283
23
  connected_sessions_[session_id].first = id;
284
23
  session->Accept(ws_key);
285
23
  delegate_->StartSession(session_id, id);
286
}
287
288
55
void InspectorSocketServer::SessionTerminated(int session_id) {
289
55
  if (Session(session_id) == nullptr) {
290
    return;
291
  }
292
55
  bool was_attached = connected_sessions_[session_id].first != "";
293
55
  if (was_attached) {
294
23
    delegate_->EndSession(session_id);
295
  }
296
55
  connected_sessions_.erase(session_id);
297
55
  if (connected_sessions_.empty()) {
298

71
    if (was_attached && state_ == ServerState::kRunning
299

52
        && !server_sockets_.empty()) {
300
6
      PrintDebuggerReadyMessage(host_,
301
                                server_sockets_,
302
4
                                delegate_->GetTargetIds(),
303
2
                                inspect_publish_uid_.console,
304
2
                                out_);
305
    }
306
50
    if (state_ == ServerState::kStopped) {
307
21
      delegate_.reset();
308
    }
309
  }
310
}
311
312
32
bool InspectorSocketServer::HandleGetRequest(int session_id,
313
                                             const std::string& host,
314
                                             const std::string& path) {
315
32
  SocketSession* session = Session(session_id);
316
32
  InspectorSocket* socket = session->ws_socket();
317
32
  if (!inspect_publish_uid_.http) {
318
1
    SendHttpNotFound(socket);
319
1
    return true;
320
  }
321
31
  const char* command = MatchPathSegment(path.c_str(), "/json");
322
31
  if (command == nullptr)
323
    return false;
324
325

31
  if (MatchPathSegment(command, "list") || command[0] == '\0') {
326
27
    SendListResponse(socket, host, session);
327
27
    return true;
328
4
  } else if (MatchPathSegment(command, "protocol")) {
329
    SendProtocolJson(socket);
330
    return true;
331
4
  } else if (MatchPathSegment(command, "version")) {
332
1
    SendVersionResponse(socket);
333
1
    return true;
334
  }
335
3
  return false;
336
}
337
338
27
void InspectorSocketServer::SendListResponse(InspectorSocket* socket,
339
                                             const std::string& host,
340
                                             SocketSession* session) {
341
54
  std::vector<std::map<std::string, std::string>> response;
342
48
  for (const std::string& id : delegate_->GetTargetIds()) {
343
21
    response.push_back(std::map<std::string, std::string>());
344
21
    std::map<std::string, std::string>& target_map = response.back();
345
21
    target_map["description"] = "node.js instance";
346
42
    target_map["faviconUrl"] =
347
21
                        "https://nodejs.org/static/images/favicons/favicon.ico";
348
21
    target_map["id"] = id;
349
21
    target_map["title"] = delegate_->GetTargetTitle(id);
350
21
    Escape(&target_map["title"]);
351
21
    target_map["type"] = "node";
352
    // This attribute value is a "best effort" URL that is passed as a JSON
353
    // string. It is not guaranteed to resolve to a valid resource.
354
21
    target_map["url"] = delegate_->GetTargetUrl(id);
355
21
    Escape(&target_map["url"]);
356
357
42
    std::string detected_host = host;
358
21
    if (detected_host.empty()) {
359
      detected_host = FormatHostPort(socket->GetHost(),
360
                                     session->server_port());
361
    }
362
42
    std::string formatted_address = FormatAddress(detected_host, id, false);
363
42
    target_map["devtoolsFrontendUrl"] = GetFrontendURL(false,
364
21
                                                       formatted_address);
365
    // The compat URL is for Chrome browsers older than 66.0.3345.0
366
42
    target_map["devtoolsFrontendUrlCompat"] = GetFrontendURL(true,
367
21
                                                             formatted_address);
368
21
    target_map["webSocketDebuggerUrl"] = FormatAddress(detected_host, id, true);
369
  }
370
27
  SendHttpResponse(socket, MapsToString(response), 200);
371
27
}
372
373
42
std::string InspectorSocketServer::GetFrontendURL(bool is_compat,
374
    const std::string &formatted_address) {
375
84
  std::ostringstream frontend_url;
376
42
  frontend_url << "devtools://devtools/bundled/";
377
42
  frontend_url << (is_compat ? "inspector" : "js_app");
378
42
  frontend_url << ".html?experiments=true&v8only=true&ws=";
379
42
  frontend_url << formatted_address;
380
84
  return frontend_url.str();
381
}
382
383
89
bool InspectorSocketServer::Start() {
384
89
  CHECK_NOT_NULL(delegate_);
385
89
  CHECK_EQ(state_, ServerState::kNew);
386
178
  std::unique_ptr<SocketServerDelegate> delegate_holder;
387
  // We will return it if startup is successful
388
89
  delegate_.swap(delegate_holder);
389
  struct addrinfo hints;
390
89
  memset(&hints, 0, sizeof(hints));
391
89
  hints.ai_flags = AI_NUMERICSERV;
392
89
  hints.ai_socktype = SOCK_STREAM;
393
  uv_getaddrinfo_t req;
394
178
  const std::string port_string = std::to_string(port_);
395
89
  int err = uv_getaddrinfo(loop_, &req, nullptr, host_.c_str(),
396
89
                           port_string.c_str(), &hints);
397
89
  if (err < 0) {
398
    if (out_ != nullptr) {
399
      fprintf(out_, "Unable to resolve \"%s\": %s\n", host_.c_str(),
400
              uv_strerror(err));
401
    }
402
    return false;
403
  }
404
183
  for (addrinfo* address = req.addrinfo; address != nullptr;
405
94
       address = address->ai_next) {
406
188
    auto server_socket = ServerSocketPtr(new ServerSocket(this));
407
94
    err = server_socket->Listen(address->ai_addr, loop_);
408
94
    if (err == 0)
409
88
      server_sockets_.push_back(std::move(server_socket));
410
  }
411
89
  uv_freeaddrinfo(req.addrinfo);
412
413
  // We only show error if we failed to start server on all addresses. We only
414
  // show one error, for the last address.
415
89
  if (server_sockets_.empty()) {
416
3
    if (out_ != nullptr) {
417
1
      fprintf(out_, "Starting inspector on %s:%d failed: %s\n",
418
1
              host_.c_str(), port_, uv_strerror(err));
419
1
      fflush(out_);
420
    }
421
3
    return false;
422
  }
423
86
  delegate_.swap(delegate_holder);
424
86
  state_ = ServerState::kRunning;
425
258
  PrintDebuggerReadyMessage(host_,
426
                            server_sockets_,
427
172
                            delegate_->GetTargetIds(),
428
86
                            inspect_publish_uid_.console,
429
86
                            out_);
430
86
  return true;
431
}
432
433
102
void InspectorSocketServer::Stop() {
434
102
  if (state_ == ServerState::kStopped)
435
16
    return;
436
86
  CHECK_EQ(state_, ServerState::kRunning);
437
86
  state_ = ServerState::kStopped;
438
86
  server_sockets_.clear();
439
86
  if (done())
440
65
    delegate_.reset();
441
}
442
443
25
void InspectorSocketServer::TerminateConnections() {
444
28
  for (const auto& key_value : connected_sessions_)
445
3
    key_value.second.second->Close();
446
25
}
447
448
24
bool InspectorSocketServer::TargetExists(const std::string& id) {
449
48
  const std::vector<std::string>& target_ids = delegate_->GetTargetIds();
450
24
  const auto& found = std::find(target_ids.begin(), target_ids.end(), id);
451
48
  return found != target_ids.end();
452
}
453
454
90
int InspectorSocketServer::Port() const {
455
90
  if (!server_sockets_.empty()) {
456
90
    return server_sockets_[0]->port();
457
  }
458
  return port_;
459
}
460
461
55
void InspectorSocketServer::Accept(int server_port,
462
                                   uv_stream_t* server_socket) {
463
  std::unique_ptr<SocketSession> session(
464
110
      new SocketSession(this, next_session_id_++, server_port));
465
466
  InspectorSocket::DelegatePointer delegate =
467
      InspectorSocket::DelegatePointer(
468
110
          new SocketSession::Delegate(this, session->id()));
469
470
  InspectorSocket::Pointer inspector =
471
110
      InspectorSocket::Accept(server_socket, std::move(delegate));
472
55
  if (inspector) {
473
55
    session->Own(std::move(inspector));
474
55
    connected_sessions_[session->id()].second = std::move(session);
475
  }
476
55
}
477
478
1240
void InspectorSocketServer::Send(int session_id, const std::string& message) {
479
1240
  SocketSession* session = Session(session_id);
480
1240
  if (session != nullptr) {
481
1240
    session->Send(message);
482
  }
483
1240
}
484
485
94
void InspectorSocketServer::CloseServerSocket(ServerSocket* server) {
486
94
  server->Close();
487
94
}
488
489
// InspectorSession tracking
490
55
SocketSession::SocketSession(InspectorSocketServer* server, int id,
491
55
                             int server_port)
492
55
    : id_(id), server_port_(server_port) {}
493
494
1240
void SocketSession::Send(const std::string& message) {
495
1240
  ws_socket_->Write(message.data(), message.length());
496
1240
}
497
498
32
void SocketSession::Delegate::OnHttpGet(const std::string& host,
499
                                        const std::string& path) {
500
32
  if (!server_->HandleGetRequest(session_id_, host, path))
501
3
    Session()->ws_socket()->CancelHandshake();
502
32
}
503
504
24
void SocketSession::Delegate::OnSocketUpgrade(const std::string& host,
505
                                              const std::string& path,
506
                                              const std::string& ws_key) {
507
48
  std::string id = path.empty() ? path : path.substr(1);
508
24
  server_->SessionStarted(session_id_, id, ws_key);
509
24
}
510
511
135
void SocketSession::Delegate::OnWsFrame(const std::vector<char>& data) {
512
135
  server_->MessageReceived(session_id_,
513
270
                           std::string(data.data(), data.size()));
514
135
}
515
516
// ServerSocket implementation
517
88
int ServerSocket::DetectPort() {
518
  sockaddr_storage addr;
519
88
  int len = sizeof(addr);
520
88
  int err = uv_tcp_getsockname(&tcp_socket_,
521
88
                               reinterpret_cast<struct sockaddr*>(&addr), &len);
522
88
  if (err != 0)
523
    return err;
524
  int port;
525
88
  if (addr.ss_family == AF_INET6)
526
7
    port = reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port;
527
  else
528
81
    port = reinterpret_cast<const sockaddr_in*>(&addr)->sin_port;
529
88
  port_ = ntohs(port);
530
88
  return err;
531
}
532
533
94
int ServerSocket::Listen(sockaddr* addr, uv_loop_t* loop) {
534
94
  uv_tcp_t* server = &tcp_socket_;
535
94
  CHECK_EQ(0, uv_tcp_init(loop, server));
536
94
  int err = uv_tcp_bind(server, addr, 0);
537
94
  if (err == 0) {
538
    // 511 is the value used by a 'net' module by default
539
    err = uv_listen(reinterpret_cast<uv_stream_t*>(server), 511,
540
90
                    ServerSocket::SocketConnectedCallback);
541
  }
542
94
  if (err == 0) {
543
88
    err = DetectPort();
544
  }
545
94
  return err;
546
}
547
548
// static
549
55
void ServerSocket::SocketConnectedCallback(uv_stream_t* tcp_socket,
550
                                           int status) {
551
55
  if (status == 0) {
552
55
    ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket);
553
    // Memory is freed when the socket closes.
554
55
    server_socket->server_->Accept(server_socket->port_, tcp_socket);
555
  }
556
55
}
557
}  // namespace inspector
558
}  // namespace node