GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/inspector_socket.cc Lines: 297 340 87.4 %
Date: 2017-06-14 Branches: 100 163 61.3 %

Line Branch Exec Source
1
#include "inspector_socket.h"
2
#include "util.h"
3
#include "util-inl.h"
4
5
#define NODE_WANT_INTERNALS 1
6
#include "base64.h"
7
8
#include "openssl/sha.h"  // Sha-1 hash
9
10
#include <string.h>
11
#include <vector>
12
13
#define ACCEPT_KEY_LENGTH base64_encoded_size(20)
14
#define BUFFER_GROWTH_CHUNK_SIZE 1024
15
16
#define DUMP_READS 0
17
#define DUMP_WRITES 0
18
19
namespace node {
20
namespace inspector {
21
22
static const char CLOSE_FRAME[] = {'\x88', '\x00'};
23
24
enum ws_decode_result {
25
  FRAME_OK, FRAME_INCOMPLETE, FRAME_CLOSE, FRAME_ERROR
26
};
27
28
#if DUMP_READS || DUMP_WRITES
29
static void dump_hex(const char* buf, size_t len) {
30
  const char* ptr = buf;
31
  const char* end = ptr + len;
32
  const char* cptr;
33
  char c;
34
  int i;
35
36
  while (ptr < end) {
37
    cptr = ptr;
38
    for (i = 0; i < 16 && ptr < end; i++) {
39
      printf("%2.2X  ", static_cast<unsigned char>(*(ptr++)));
40
    }
41
    for (i = 72 - (i * 4); i > 0; i--) {
42
      printf(" ");
43
    }
44
    for (i = 0; i < 16 && cptr < end; i++) {
45
      c = *(cptr++);
46
      printf("%c", (c > 0x19) ? c : '.');
47
    }
48
    printf("\n");
49
  }
50
  printf("\n\n");
51
}
52
#endif
53
54
60
static void remove_from_beginning(std::vector<char>* buffer, size_t count) {
55
60
  buffer->erase(buffer->begin(), buffer->begin() + count);
56
60
}
57
58
20
static void dispose_inspector(uv_handle_t* handle) {
59
20
  InspectorSocket* inspector = inspector_from_stream(handle);
60
  inspector_cb close =
61
20
      inspector->ws_mode ? inspector->ws_state->close_cb : nullptr;
62
20
  inspector->buffer.clear();
63
20
  delete inspector->ws_state;
64
20
  inspector->ws_state = nullptr;
65
20
  if (close) {
66
5
    close(inspector, 0);
67
  }
68
20
}
69
70
5
static void close_connection(InspectorSocket* inspector) {
71
5
  uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->tcp);
72
5
  if (!uv_is_closing(socket)) {
73
5
    uv_read_stop(reinterpret_cast<uv_stream_t*>(socket));
74
5
    uv_close(socket, dispose_inspector);
75
  }
76
5
}
77
78
410
struct WriteRequest {
79
410
  WriteRequest(InspectorSocket* inspector, const char* data, size_t size)
80
      : inspector(inspector)
81
      , storage(data, data + size)
82
410
      , buf(uv_buf_init(&storage[0], storage.size())) {}
83
84
413
  static WriteRequest* from_write_req(uv_write_t* req) {
85
413
    return node::ContainerOf(&WriteRequest::req, req);
86
  }
87
88
  InspectorSocket* const inspector;
89
  std::vector<char> storage;
90
  uv_write_t req;
91
  uv_buf_t buf;
92
};
93
94
// Cleanup
95
409
static void write_request_cleanup(uv_write_t* req, int status) {
96
409
  delete WriteRequest::from_write_req(req);
97
409
}
98
99
410
static int write_to_client(InspectorSocket* inspector,
100
                           const char* msg,
101
                           size_t len,
102
                           uv_write_cb write_cb = write_request_cleanup) {
103
#if DUMP_WRITES
104
  printf("%s (%ld bytes):\n", __FUNCTION__, len);
105
  dump_hex(msg, len);
106
#endif
107
108
  // Freed in write_request_cleanup
109
410
  WriteRequest* wr = new WriteRequest(inspector, msg, len);
110
410
  uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(&inspector->tcp);
111
410
  return uv_write(&wr->req, stream, &wr->buf, 1, write_cb) < 0;
112
}
113
114
// Constants for hybi-10 frame format.
115
116
typedef int OpCode;
117
118
const OpCode kOpCodeContinuation = 0x0;
119
const OpCode kOpCodeText = 0x1;
120
const OpCode kOpCodeBinary = 0x2;
121
const OpCode kOpCodeClose = 0x8;
122
const OpCode kOpCodePing = 0x9;
123
const OpCode kOpCodePong = 0xA;
124
125
const unsigned char kFinalBit = 0x80;
126
const unsigned char kReserved1Bit = 0x40;
127
const unsigned char kReserved2Bit = 0x20;
128
const unsigned char kReserved3Bit = 0x10;
129
const unsigned char kOpCodeMask = 0xF;
130
const unsigned char kMaskBit = 0x80;
131
const unsigned char kPayloadLengthMask = 0x7F;
132
133
const size_t kMaxSingleBytePayloadLength = 125;
134
const size_t kTwoBytePayloadLengthField = 126;
135
const size_t kEightBytePayloadLengthField = 127;
136
const size_t kMaskingKeyWidthInBytes = 4;
137
138
383
static std::vector<char> encode_frame_hybi17(const char* message,
139
                                             size_t data_length) {
140
383
  std::vector<char> frame;
141
383
  OpCode op_code = kOpCodeText;
142
383
  frame.push_back(kFinalBit | op_code);
143
383
  if (data_length <= kMaxSingleBytePayloadLength) {
144
53
    frame.push_back(static_cast<char>(data_length));
145
330
  } else if (data_length <= 0xFFFF) {
146
330
    frame.push_back(kTwoBytePayloadLengthField);
147
330
    frame.push_back((data_length & 0xFF00) >> 8);
148
330
    frame.push_back(data_length & 0xFF);
149
  } else {
150
    frame.push_back(kEightBytePayloadLengthField);
151
    char extended_payload_length[8];
152
    size_t remaining = data_length;
153
    // Fill the length into extended_payload_length in the network byte order.
154
    for (int i = 0; i < 8; ++i) {
155
      extended_payload_length[7 - i] = remaining & 0xFF;
156
      remaining >>= 8;
157
    }
158
    frame.insert(frame.end(), extended_payload_length,
159
                 extended_payload_length + 8);
160
    ASSERT_EQ(0, remaining);
161
  }
162
383
  frame.insert(frame.end(), message, message + data_length);
163
383
  return frame;
164
}
165
166
44
static ws_decode_result decode_frame_hybi17(const std::vector<char>& buffer,
167
                                            bool client_frame,
168
                                            int* bytes_consumed,
169
                                            std::vector<char>* output,
170
                                            bool* compressed) {
171
44
  *bytes_consumed = 0;
172
44
  if (buffer.size() < 2)
173
    return FRAME_INCOMPLETE;
174
175
44
  auto it = buffer.begin();
176
177
44
  unsigned char first_byte = *it++;
178
44
  unsigned char second_byte = *it++;
179
180
44
  bool final = (first_byte & kFinalBit) != 0;
181
44
  bool reserved1 = (first_byte & kReserved1Bit) != 0;
182
44
  bool reserved2 = (first_byte & kReserved2Bit) != 0;
183
44
  bool reserved3 = (first_byte & kReserved3Bit) != 0;
184
44
  int op_code = first_byte & kOpCodeMask;
185
44
  bool masked = (second_byte & kMaskBit) != 0;
186
44
  *compressed = reserved1;
187

44
  if (!final || reserved2 || reserved3)
188
    return FRAME_ERROR;  // Only compression extension is supported.
189
190
44
  bool closed = false;
191
44
  switch (op_code) {
192
    case kOpCodeClose:
193
1
      closed = true;
194
1
      break;
195
    case kOpCodeText:
196
43
      break;
197
    case kOpCodeBinary:        // We don't support binary frames yet.
198
    case kOpCodeContinuation:  // We don't support binary frames yet.
199
    case kOpCodePing:          // We don't support binary frames yet.
200
    case kOpCodePong:          // We don't support binary frames yet.
201
    default:
202
      return FRAME_ERROR;
203
  }
204
205
  // In Hybi-17 spec client MUST mask its frame.
206

44
  if (client_frame && !masked) {
207
    return FRAME_ERROR;
208
  }
209
210
44
  uint64_t payload_length64 = second_byte & kPayloadLengthMask;
211
44
  if (payload_length64 > kMaxSingleBytePayloadLength) {
212
    int extended_payload_length_size;
213
6
    if (payload_length64 == kTwoBytePayloadLengthField) {
214
6
      extended_payload_length_size = 2;
215
    } else if (payload_length64 == kEightBytePayloadLengthField) {
216
      extended_payload_length_size = 8;
217
    } else {
218
      return FRAME_ERROR;
219
    }
220
6
    if ((buffer.end() - it) < extended_payload_length_size)
221
      return FRAME_INCOMPLETE;
222
6
    payload_length64 = 0;
223
18
    for (int i = 0; i < extended_payload_length_size; ++i) {
224
12
      payload_length64 <<= 8;
225
12
      payload_length64 |= static_cast<unsigned char>(*it++);
226
    }
227
  }
228
229
  static const uint64_t max_payload_length = 0x7FFFFFFFFFFFFFFFull;
230
  static const size_t max_length = SIZE_MAX;
231

44
  if (payload_length64 > max_payload_length ||
232
      payload_length64 > max_length - kMaskingKeyWidthInBytes) {
233
    // WebSocket frame length too large.
234
    return FRAME_ERROR;
235
  }
236
44
  size_t payload_length = static_cast<size_t>(payload_length64);
237
238
44
  if (buffer.size() - kMaskingKeyWidthInBytes < payload_length)
239
    return FRAME_INCOMPLETE;
240
241
44
  std::vector<char>::const_iterator masking_key = it;
242
44
  std::vector<char>::const_iterator payload = it + kMaskingKeyWidthInBytes;
243
3369
  for (size_t i = 0; i < payload_length; ++i)  // Unmask the payload.
244
    output->insert(output->end(),
245
3325
                   payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes]);
246
247
44
  size_t pos = it + kMaskingKeyWidthInBytes + payload_length - buffer.begin();
248
44
  *bytes_consumed = pos;
249
44
  return closed ? FRAME_CLOSE : FRAME_OK;
250
}
251
252
43
static void invoke_read_callback(InspectorSocket* inspector,
253
                                 int status, const uv_buf_t* buf) {
254
43
  if (inspector->ws_state->read_cb) {
255
    inspector->ws_state->read_cb(
256
43
        reinterpret_cast<uv_stream_t*>(&inspector->tcp), status, buf);
257
  }
258
43
}
259
260
1
static void shutdown_complete(InspectorSocket* inspector) {
261
1
  close_connection(inspector);
262
1
}
263
264
1
static void on_close_frame_written(uv_write_t* req, int status) {
265
1
  WriteRequest* wr = WriteRequest::from_write_req(req);
266
1
  InspectorSocket* inspector = wr->inspector;
267
1
  delete wr;
268
1
  inspector->ws_state->close_sent = true;
269
1
  if (inspector->ws_state->received_close) {
270
    shutdown_complete(inspector);
271
  }
272
1
}
273
274
1
static void close_frame_received(InspectorSocket* inspector) {
275
1
  inspector->ws_state->received_close = true;
276
1
  if (!inspector->ws_state->close_sent) {
277
    invoke_read_callback(inspector, 0, 0);
278
    write_to_client(inspector, CLOSE_FRAME, sizeof(CLOSE_FRAME),
279
                    on_close_frame_written);
280
  } else {
281
1
    shutdown_complete(inspector);
282
  }
283
1
}
284
285
44
static int parse_ws_frames(InspectorSocket* inspector) {
286
44
  int bytes_consumed = 0;
287
44
  std::vector<char> output;
288
44
  bool compressed = false;
289
290
  ws_decode_result r =  decode_frame_hybi17(inspector->buffer,
291
                                            true /* client_frame */,
292
                                            &bytes_consumed, &output,
293
44
                                            &compressed);
294
  // Compressed frame means client is ignoring the headers and misbehaves
295

44
  if (compressed || r == FRAME_ERROR) {
296
    invoke_read_callback(inspector, UV_EPROTO, nullptr);
297
    close_connection(inspector);
298
    bytes_consumed = 0;
299
44
  } else if (r == FRAME_CLOSE) {
300
1
    close_frame_received(inspector);
301
1
    bytes_consumed = 0;
302

43
  } else if (r == FRAME_OK && inspector->ws_state->alloc_cb
303
43
             && inspector->ws_state->read_cb) {
304
    uv_buf_t buffer;
305
43
    size_t len = output.size();
306
    inspector->ws_state->alloc_cb(
307
        reinterpret_cast<uv_handle_t*>(&inspector->tcp),
308
43
        len, &buffer);
309
43
    CHECK_GE(buffer.len, len);
310
43
    memcpy(buffer.base, &output[0], len);
311
43
    invoke_read_callback(inspector, len, &buffer);
312
  }
313
44
  return bytes_consumed;
314
}
315
316
55
static void prepare_buffer(uv_handle_t* stream, size_t len, uv_buf_t* buf) {
317
55
  *buf = uv_buf_init(new char[len], len);
318
55
}
319
320
55
static void reclaim_uv_buf(InspectorSocket* inspector, const uv_buf_t* buf,
321
                           ssize_t read) {
322
55
  if (read > 0) {
323
39
    std::vector<char>& buffer = inspector->buffer;
324
39
    buffer.insert(buffer.end(), buf->base, buf->base + read);
325
  }
326
55
  delete[] buf->base;
327
55
}
328
329
26
static void websockets_data_cb(uv_stream_t* stream, ssize_t nread,
330
                               const uv_buf_t* buf) {
331
26
  InspectorSocket* inspector = inspector_from_stream(stream);
332
26
  reclaim_uv_buf(inspector, buf, nread);
333

26
  if (nread < 0 || nread == UV_EOF) {
334
4
    inspector->connection_eof = true;
335

4
    if (!inspector->shutting_down && inspector->ws_state->read_cb) {
336
4
      inspector->ws_state->read_cb(stream, nread, nullptr);
337
    }
338

8
    if (inspector->ws_state->close_sent &&
339
        !inspector->ws_state->received_close) {
340
      shutdown_complete(inspector);  // invoke callback
341
    }
342
  } else {
343
    #if DUMP_READS
344
      printf("%s read %ld bytes\n", __FUNCTION__, nread);
345
      if (nread > 0) {
346
        dump_hex(inspector->buffer.data() + inspector->buffer.size() - nread,
347
                 nread);
348
      }
349
    #endif
350
    // 2. Parse.
351
22
    int processed = 0;
352
44
    do {
353
44
      processed = parse_ws_frames(inspector);
354
      // 3. Fix the buffer size & length
355
44
      if (processed > 0) {
356
43
        remove_from_beginning(&inspector->buffer, processed);
357
      }
358

44
    } while (processed > 0 && !inspector->buffer.empty());
359
  }
360
26
}
361
362
6
int inspector_read_start(InspectorSocket* inspector,
363
                         uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
364
6
  ASSERT(inspector->ws_mode);
365

6
  ASSERT(!inspector->shutting_down || read_cb == nullptr);
366
6
  inspector->ws_state->close_sent = false;
367
6
  inspector->ws_state->alloc_cb = alloc_cb;
368
6
  inspector->ws_state->read_cb = read_cb;
369
  int err =
370
      uv_read_start(reinterpret_cast<uv_stream_t*>(&inspector->tcp),
371
                    prepare_buffer,
372
6
                    websockets_data_cb);
373
6
  if (err < 0) {
374
    close_connection(inspector);
375
  }
376
6
  return err;
377
}
378
379
1
void inspector_read_stop(InspectorSocket* inspector) {
380
1
  uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->tcp));
381
1
  inspector->ws_state->alloc_cb = nullptr;
382
1
  inspector->ws_state->read_cb = nullptr;
383
1
}
384
385
5
static void generate_accept_string(const std::string& client_key,
386
                                   char (*buffer)[ACCEPT_KEY_LENGTH]) {
387
  // Magic string from websockets spec.
388
  static const char ws_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
389
5
  std::string input(client_key + ws_magic);
390
  char hash[SHA_DIGEST_LENGTH];
391
5
  SHA1(reinterpret_cast<const unsigned char*>(&input[0]), input.size(),
392
10
       reinterpret_cast<unsigned char*>(hash));
393
5
  node::base64_encode(hash, sizeof(hash), *buffer, sizeof(*buffer));
394
5
}
395
396
49
static int header_value_cb(http_parser* parser, const char* at, size_t length) {
397
  static const char SEC_WEBSOCKET_KEY_HEADER[] = "Sec-WebSocket-Key";
398
49
  auto inspector = static_cast<InspectorSocket*>(parser->data);
399
49
  auto state = inspector->http_parsing_state;
400
49
  state->parsing_value = true;
401

54
  if (state->current_header.size() == sizeof(SEC_WEBSOCKET_KEY_HEADER) - 1 &&
402
      node::StringEqualNoCaseN(state->current_header.data(),
403
                               SEC_WEBSOCKET_KEY_HEADER,
404
5
                               sizeof(SEC_WEBSOCKET_KEY_HEADER) - 1)) {
405
5
    state->ws_key.append(at, length);
406
  }
407
49
  return 0;
408
}
409
410
49
static int header_field_cb(http_parser* parser, const char* at, size_t length) {
411
49
  auto inspector = static_cast<InspectorSocket*>(parser->data);
412
49
  auto state = inspector->http_parsing_state;
413
49
  if (state->parsing_value) {
414
32
    state->parsing_value = false;
415
32
    state->current_header.clear();
416
  }
417
49
  state->current_header.append(at, length);
418
49
  return 0;
419
}
420
421
17
static int path_cb(http_parser* parser, const char* at, size_t length) {
422
17
  auto inspector = static_cast<InspectorSocket*>(parser->data);
423
17
  auto state = inspector->http_parsing_state;
424
17
  state->path.append(at, length);
425
17
  return 0;
426
}
427
428
5
static void handshake_complete(InspectorSocket* inspector) {
429
5
  uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->tcp));
430
5
  handshake_cb callback = inspector->http_parsing_state->callback;
431
5
  inspector->ws_state = new ws_state_s();
432
5
  inspector->ws_mode = true;
433
  callback(inspector, kInspectorHandshakeUpgraded,
434
5
           inspector->http_parsing_state->path);
435
5
}
436
437
20
static void cleanup_http_parsing_state(InspectorSocket* inspector) {
438
20
  delete inspector->http_parsing_state;
439
20
  inspector->http_parsing_state = nullptr;
440
20
}
441
442
15
static void report_handshake_failure_cb(uv_handle_t* handle) {
443
15
  dispose_inspector(handle);
444
15
  InspectorSocket* inspector = inspector_from_stream(handle);
445
15
  handshake_cb cb = inspector->http_parsing_state->callback;
446
15
  cleanup_http_parsing_state(inspector);
447
15
  cb(inspector, kInspectorHandshakeFailed, std::string());
448
15
}
449
450
15
static void close_and_report_handshake_failure(InspectorSocket* inspector) {
451
15
  uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->tcp);
452
15
  if (uv_is_closing(socket)) {
453
    report_handshake_failure_cb(socket);
454
  } else {
455
15
    uv_read_stop(reinterpret_cast<uv_stream_t*>(socket));
456
15
    uv_close(socket, report_handshake_failure_cb);
457
  }
458
15
}
459
460
3
static void then_close_and_report_failure(uv_write_t* req, int status) {
461
3
  InspectorSocket* inspector = WriteRequest::from_write_req(req)->inspector;
462
3
  write_request_cleanup(req, status);
463
3
  close_and_report_handshake_failure(inspector);
464
3
}
465
466
3
static void handshake_failed(InspectorSocket* inspector) {
467
  const char HANDSHAKE_FAILED_RESPONSE[] =
468
      "HTTP/1.0 400 Bad Request\r\n"
469
      "Content-Type: text/html; charset=UTF-8\r\n\r\n"
470
3
      "WebSockets request was expected\r\n";
471
  write_to_client(inspector, HANDSHAKE_FAILED_RESPONSE,
472
                  sizeof(HANDSHAKE_FAILED_RESPONSE) - 1,
473
3
                  then_close_and_report_failure);
474
3
}
475
476
// init_handshake references message_complete_cb
477
static void init_handshake(InspectorSocket* socket);
478
479
17
static int message_complete_cb(http_parser* parser) {
480
17
  InspectorSocket* inspector = static_cast<InspectorSocket*>(parser->data);
481
17
  struct http_parsing_state_s* state = inspector->http_parsing_state;
482
17
  if (parser->method != HTTP_GET) {
483
    handshake_failed(inspector);
484
17
  } else if (!parser->upgrade) {
485
12
    if (state->callback(inspector, kInspectorHandshakeHttpGet, state->path)) {
486
9
      init_handshake(inspector);
487
    } else {
488
3
      handshake_failed(inspector);
489
    }
490
5
  } else if (state->ws_key.empty()) {
491
    handshake_failed(inspector);
492
5
  } else if (state->callback(inspector, kInspectorHandshakeUpgrading,
493
5
                             state->path)) {
494
    char accept_string[ACCEPT_KEY_LENGTH];
495
5
    generate_accept_string(state->ws_key, &accept_string);
496
    const char accept_ws_prefix[] = "HTTP/1.1 101 Switching Protocols\r\n"
497
                                    "Upgrade: websocket\r\n"
498
                                    "Connection: Upgrade\r\n"
499
5
                                    "Sec-WebSocket-Accept: ";
500
5
    const char accept_ws_suffix[] = "\r\n\r\n";
501
5
    std::string reply(accept_ws_prefix, sizeof(accept_ws_prefix) - 1);
502
5
    reply.append(accept_string, sizeof(accept_string));
503
5
    reply.append(accept_ws_suffix, sizeof(accept_ws_suffix) - 1);
504
5
    if (write_to_client(inspector, &reply[0], reply.size()) >= 0) {
505
5
      handshake_complete(inspector);
506
5
      inspector->http_parsing_state->done = true;
507
    } else {
508
      close_and_report_handshake_failure(inspector);
509
5
    }
510
  } else {
511
    handshake_failed(inspector);
512
  }
513
17
  return 0;
514
}
515
516
29
static void data_received_cb(uv_stream_s* tcp, ssize_t nread,
517
                             const uv_buf_t* buf) {
518
#if DUMP_READS
519
  if (nread >= 0) {
520
    printf("%s (%ld bytes)\n", __FUNCTION__, nread);
521
    dump_hex(buf->base, nread);
522
  } else {
523
    printf("[%s:%d] %s\n", __FUNCTION__, __LINE__, uv_err_name(nread));
524
  }
525
#endif
526
29
  InspectorSocket* inspector = inspector_from_stream(tcp);
527
29
  reclaim_uv_buf(inspector, buf, nread);
528

29
  if (nread < 0 || nread == UV_EOF) {
529
12
    close_and_report_handshake_failure(inspector);
530
  } else {
531
17
    http_parsing_state_s* state = inspector->http_parsing_state;
532
17
    http_parser* parser = &state->parser;
533
    http_parser_execute(parser, &state->parser_settings,
534
17
                        inspector->buffer.data(), nread);
535
17
    remove_from_beginning(&inspector->buffer, nread);
536
17
    if (parser->http_errno != HPE_OK) {
537
      handshake_failed(inspector);
538
    }
539
17
    if (inspector->http_parsing_state->done) {
540
5
      cleanup_http_parsing_state(inspector);
541
    }
542
  }
543
29
}
544
545
29
static void init_handshake(InspectorSocket* socket) {
546
29
  http_parsing_state_s* state = socket->http_parsing_state;
547
29
  CHECK_NE(state, nullptr);
548
29
  state->current_header.clear();
549
29
  state->ws_key.clear();
550
29
  state->path.clear();
551
29
  state->done = false;
552
29
  http_parser_init(&state->parser, HTTP_REQUEST);
553
29
  state->parser.data = socket;
554
29
  http_parser_settings* settings = &state->parser_settings;
555
29
  http_parser_settings_init(settings);
556
29
  settings->on_header_field = header_field_cb;
557
29
  settings->on_header_value = header_value_cb;
558
29
  settings->on_message_complete = message_complete_cb;
559
29
  settings->on_url = path_cb;
560
29
}
561
562
20
int inspector_accept(uv_stream_t* server, InspectorSocket* socket,
563
                     handshake_cb callback) {
564
20
  ASSERT_NE(callback, nullptr);
565
20
  CHECK_EQ(socket->http_parsing_state, nullptr);
566
567
20
  socket->http_parsing_state = new http_parsing_state_s();
568
20
  uv_stream_t* tcp = reinterpret_cast<uv_stream_t*>(&socket->tcp);
569
20
  int err = uv_tcp_init(server->loop, &socket->tcp);
570
571
20
  if (err == 0) {
572
20
    err = uv_accept(server, tcp);
573
  }
574
20
  if (err == 0) {
575
20
    init_handshake(socket);
576
20
    socket->http_parsing_state->callback = callback;
577
    err = uv_read_start(tcp, prepare_buffer,
578
20
                        data_received_cb);
579
  }
580
20
  if (err != 0) {
581
    uv_close(reinterpret_cast<uv_handle_t*>(tcp), NULL);
582
  }
583
20
  return err;
584
}
585
586
401
void inspector_write(InspectorSocket* inspector, const char* data,
587
                     size_t len) {
588
401
  if (inspector->ws_mode) {
589
383
    std::vector<char> output = encode_frame_hybi17(data, len);
590
383
    write_to_client(inspector, &output[0], output.size());
591
  } else {
592
18
    write_to_client(inspector, data, len);
593
  }
594
401
}
595
596
5
void inspector_close(InspectorSocket* inspector,
597
                     inspector_cb callback) {
598
  // libuv throws assertions when closing stream that's already closed - we
599
  // need to do the same.
600
5
  ASSERT(!uv_is_closing(reinterpret_cast<uv_handle_t*>(&inspector->tcp)));
601
5
  ASSERT(!inspector->shutting_down);
602
5
  inspector->shutting_down = true;
603
5
  inspector->ws_state->close_cb = callback;
604
5
  if (inspector->connection_eof) {
605
4
    close_connection(inspector);
606
  } else {
607
1
    inspector_read_stop(inspector);
608
    write_to_client(inspector, CLOSE_FRAME, sizeof(CLOSE_FRAME),
609
1
                    on_close_frame_written);
610
1
    inspector_read_start(inspector, nullptr, nullptr);
611
  }
612
5
}
613
614
bool inspector_is_active(const InspectorSocket* inspector) {
615
  const uv_handle_t* tcp =
616
      reinterpret_cast<const uv_handle_t*>(&inspector->tcp);
617
  return !inspector->shutting_down && !uv_is_closing(tcp);
618
}
619
620
void InspectorSocket::reinit() {
621
  http_parsing_state = nullptr;
622
  ws_state = nullptr;
623
  buffer.clear();
624
  ws_mode = false;
625
  shutting_down = false;
626
  connection_eof = false;
627
}
628
629
}  // namespace inspector
630
}  // namespace node