GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../test/cctest/test_inspector_socket.cc Lines: 451 469 96.2 %
Date: 2019-01-07 12:15:22 Branches: 262 518 50.6 %

Line Branch Exec Source
1
#include "inspector_socket.h"
2
#include "gtest/gtest.h"
3
4
#include <queue>
5
6
#define PORT 9444
7
8
namespace {
9
10
using node::inspector::InspectorSocket;
11
12
static const int MAX_LOOP_ITERATIONS = 10000;
13
14
static uv_loop_t loop;
15
16
class Timeout {
17
 public:
18
248
  explicit Timeout(uv_loop_t* loop) : timed_out(false), done_(false) {
19
248
    uv_timer_init(loop, &timer_);
20
248
    uv_timer_start(&timer_, Timeout::set_flag, 5000, 0);
21
248
  }
22
23
248
  ~Timeout() {
24
248
    uv_timer_stop(&timer_);
25
248
    uv_close(reinterpret_cast<uv_handle_t*>(&timer_), mark_done);
26
744
    while (!done_) {
27
248
      uv_run(&loop, UV_RUN_NOWAIT);
28
    }
29
248
  }
30
31
  bool timed_out;
32
33
 private:
34
  static void set_flag(uv_timer_t* timer) {
35
    Timeout* t = node::ContainerOf(&Timeout::timer_, timer);
36
    t->timed_out = true;
37
  }
38
39
248
  static void mark_done(uv_handle_t* timer) {
40
    Timeout* t = node::ContainerOf(&Timeout::timer_,
41
248
        reinterpret_cast<uv_timer_t*>(timer));
42
248
    t->done_ = true;
43
248
  }
44
45
  bool done_;
46
  uv_timer_t timer_;
47
};
48
49
#define SPIN_WHILE(condition)                                                  \
50
  {                                                                            \
51
    Timeout timeout(&loop);                                                    \
52
    while ((condition) && !timeout.timed_out) {                                \
53
      uv_run(&loop, UV_RUN_NOWAIT);                                            \
54
    }                                                                          \
55
    ASSERT_FALSE((condition));                                                 \
56
  }
57
58
enum inspector_handshake_event {
59
  kInspectorHandshakeHttpGet,
60
  kInspectorHandshakeUpgraded,
61
  kInspectorHandshakeNoEvents
62
};
63
64
struct expectations {
65
  std::string actual_data;
66
  size_t actual_offset;
67
  size_t actual_end;
68
  int err_code;
69
};
70
71
static bool waiting_to_close = true;
72
73
37
void handle_closed(uv_handle_t* handle) {
74
37
  waiting_to_close = false;
75
37
}
76
77
41
static void really_close(uv_handle_t* handle) {
78
41
  waiting_to_close = true;
79
41
  if (!uv_is_closing(handle)) {
80
37
    uv_close(handle, handle_closed);
81


37
    SPIN_WHILE(waiting_to_close);
82
  }
83
}
84
85
45
static void buffer_alloc_cb(uv_handle_t* stream, size_t len, uv_buf_t* buf) {
86
45
  buf->base = new char[len];
87
45
  buf->len = len;
88
45
}
89
90
class TestInspectorDelegate;
91
92
static TestInspectorDelegate* delegate = nullptr;
93
94
// Gtest asserts can't be used in dtor directly.
95
20
static void assert_is_delegate(TestInspectorDelegate* d) {
96

20
  GTEST_ASSERT_EQ(delegate, d);
97
}
98
99
class TestInspectorDelegate : public InspectorSocket::Delegate {
100
 public:
101
  using delegate_fn = void(*)(inspector_handshake_event, const std::string&,
102
                              bool* should_continue);
103
104
20
  TestInspectorDelegate() : inspector_ready(false),
105
                            last_event(kInspectorHandshakeNoEvents),
106
                            handshake_events(0),
107
                            handshake_delegate_(stop_if_stop_path),
108
20
                            fail_on_ws_frame_(false) { }
109
110
60
  ~TestInspectorDelegate() {
111
20
    assert_is_delegate(this);
112
20
    delegate = nullptr;
113
40
  }
114
115
5
  void OnHttpGet(const std::string& host, const std::string& path) override {
116
5
    process(kInspectorHandshakeHttpGet, path);
117
5
  }
118
119
13
  void OnSocketUpgrade(const std::string& host, const std::string& path,
120
                       const std::string& ws_key) override {
121
13
    ws_key_ = ws_key;
122
13
    process(kInspectorHandshakeUpgraded, path);
123
13
  }
124
125
10
  void OnWsFrame(const std::vector<char>& buffer) override {
126

20
    ASSERT_FALSE(fail_on_ws_frame_);
127
10
    frames.push(buffer);
128
  }
129
130
5
  void SetDelegate(delegate_fn d) {
131
5
    handshake_delegate_ = d;
132
5
  }
133
134
20
  void SetInspector(InspectorSocket::Pointer inspector) {
135
20
    socket_ = std::move(inspector);
136
20
  }
137
138
8
  void Write(const char* buf, size_t len) {
139
8
    socket_->Write(buf, len);
140
8
  }
141
142
  void ExpectReadError() {
143
    SPIN_WHILE(frames.empty() || !frames.back().empty());
144
  }
145
146
4
  void ExpectData(const char* data, size_t len) {
147
4
    const char* cur = data;
148
4
    const char* end = data + len;
149
17
    while (cur < end) {
150



9
      SPIN_WHILE(frames.empty());
151
9
      const std::vector<char>& frame = frames.front();
152
9
      EXPECT_FALSE(frame.empty());
153
9
      auto c = frame.begin();
154


1000325
      for (; c < frame.end() && cur < end; c++) {
155

1000325
        GTEST_ASSERT_EQ(*cur, *c) << "Character #" << cur - data;
156
1000325
        cur = cur + 1;
157
      }
158
9
      EXPECT_EQ(c, frame.end());
159
9
      frames.pop();
160
    }
161
  }
162
163
1
  void FailOnWsFrame() {
164
1
    fail_on_ws_frame_ = true;
165
1
  }
166
167
1
  void WaitForDispose() {
168


1
    SPIN_WHILE(delegate != nullptr);
169
  }
170
171
3
  void Close() {
172
3
    socket_.reset();
173
3
  }
174
175
  bool inspector_ready;
176
  std::string last_path;  // NOLINT(runtime/string)
177
  inspector_handshake_event last_event;
178
  int handshake_events;
179
  std::queue<std::vector<char>> frames;
180
181
 private:
182
11
  static void stop_if_stop_path(enum inspector_handshake_event state,
183
                              const std::string& path, bool* cont) {
184

11
    *cont = path.empty() || path != "/close";
185
11
  }
186
187
  void process(inspector_handshake_event event, const std::string& path);
188
189
  delegate_fn handshake_delegate_;
190
  InspectorSocket::Pointer socket_;
191
  std::string ws_key_;
192
  bool fail_on_ws_frame_;
193
};
194
195
static bool connected = false;
196
static uv_tcp_t server, client_socket;
197
static const char SERVER_CLOSE_FRAME[] = {'\x88', '\x00'};
198
199
struct read_expects {
200
  const char* expected;
201
  size_t expected_len;
202
  size_t pos;
203
  bool read_expected;
204
  bool callback_called;
205
};
206
207
static const char HANDSHAKE_REQ[] = "GET /ws/path HTTP/1.1\r\n"
208
                                    "Host: localhost:9229\r\n"
209
                                    "Upgrade: websocket\r\n"
210
                                    "Connection: Upgrade\r\n"
211
                                    "Sec-WebSocket-Key: aaa==\r\n"
212
                                    "Sec-WebSocket-Version: 13\r\n\r\n";
213
214
18
void TestInspectorDelegate::process(inspector_handshake_event event,
215
                                    const std::string& path) {
216
18
  inspector_ready = event == kInspectorHandshakeUpgraded;
217
18
  last_event = event;
218
18
  if (path.empty()) {
219
    last_path = "@@@ Nothing received @@@";
220
  } else {
221
18
    last_path = path;
222
  }
223
18
  handshake_events++;
224
18
  bool should_continue = true;
225
18
  handshake_delegate_(event, path, &should_continue);
226
18
  if (should_continue) {
227
16
    if (inspector_ready)
228
12
      socket_->AcceptUpgrade(ws_key_);
229
  } else {
230
2
    socket_->CancelHandshake();
231
  }
232
18
}
233
234
20
static void on_new_connection(uv_stream_t* server, int status) {
235

20
  GTEST_ASSERT_EQ(0, status);
236
20
  connected = true;
237
20
  delegate = new TestInspectorDelegate();
238
  delegate->SetInspector(
239
      InspectorSocket::Accept(server,
240
20
                              InspectorSocket::DelegatePointer(delegate)));
241

20
  GTEST_ASSERT_NE(nullptr, delegate);
242
}
243
244
118
void write_done(uv_write_t* req, int status) { req->data = nullptr; }
245
246
118
static void do_write(const char* data, int len) {
247
  uv_write_t req;
248
118
  bool done = false;
249
118
  req.data = &done;
250
  uv_buf_t buf[1];
251
118
  buf[0].base = const_cast<char*>(data);
252
118
  buf[0].len = len;
253

118
  GTEST_ASSERT_EQ(0,
254
                  uv_write(&req, reinterpret_cast<uv_stream_t*>(&client_socket),
255
118
                           buf, 1, write_done));
256


118
  SPIN_WHILE(req.data);
257
}
258
259
45
static void check_data_cb(read_expects* expectation, ssize_t nread,
260
                          const uv_buf_t* buf, bool* retval) {
261
45
  *retval = false;
262

45
  EXPECT_TRUE(nread >= 0 && nread != UV_EOF);
263
  ssize_t i;
264
  char c, actual;
265
45
  CHECK_GT(expectation->expected_len, 0);
266

1002302
  for (i = 0; i < nread && expectation->pos <= expectation->expected_len; i++) {
267
1002257
    c = expectation->expected[expectation->pos++];
268
1002257
    actual = buf->base[i];
269
1002257
    if (c != actual) {
270
      fprintf(stderr, "Unexpected character at position %zd\n",
271
              expectation->pos - 1);
272
      GTEST_ASSERT_EQ(c, actual);
273
    }
274
  }
275

45
  GTEST_ASSERT_EQ(i, nread);
276
45
  delete[] buf->base;
277
45
  if (expectation->pos == expectation->expected_len) {
278
30
    expectation->read_expected = true;
279
30
    *retval = true;
280
  }
281
}
282
283
45
static void check_data_cb(uv_stream_t* stream, ssize_t nread,
284
                          const uv_buf_t* buf) {
285
45
  bool retval = false;
286
45
  read_expects* expects = static_cast<read_expects*>(stream->data);
287
45
  expects->callback_called = true;
288
45
  check_data_cb(expects, nread, buf, &retval);
289
45
  if (retval) {
290
30
    stream->data = nullptr;
291
30
    uv_read_stop(stream);
292
  }
293
45
}
294
295
30
static read_expects prepare_expects(const char* data, size_t len) {
296
  read_expects expectation;
297
30
  expectation.expected = data;
298
30
  expectation.expected_len = len;
299
30
  expectation.pos = 0;
300
30
  expectation.read_expected = false;
301
30
  expectation.callback_called = false;
302
30
  return expectation;
303
}
304
305
static void fail_callback(uv_stream_t* stream, ssize_t nread,
306
                          const uv_buf_t* buf) {
307
  if (nread < 0) {
308
    fprintf(stderr, "IO error: %s\n", uv_strerror(nread));
309
  } else {
310
    fprintf(stderr, "Read %zd bytes\n", nread);
311
  }
312
  ASSERT_TRUE(false);  // Shouldn't have been called
313
}
314
315
1
static void expect_nothing_on_client() {
316
1
  uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(&client_socket);
317
1
  int err = uv_read_start(stream, buffer_alloc_cb, fail_callback);
318

2
  GTEST_ASSERT_EQ(0, err);
319
10001
  for (int i = 0; i < MAX_LOOP_ITERATIONS; i++)
320
10000
    uv_run(&loop, UV_RUN_NOWAIT);
321
1
  uv_read_stop(stream);
322
}
323
324
30
static void expect_on_client(const char* data, size_t len) {
325
30
  read_expects expectation = prepare_expects(data, len);
326
30
  client_socket.data = &expectation;
327
  uv_read_start(reinterpret_cast<uv_stream_t*>(&client_socket),
328
30
                buffer_alloc_cb, check_data_cb);
329


30
  SPIN_WHILE(!expectation.read_expected);
330
}
331
332
12
static void expect_handshake() {
333
  const char UPGRADE_RESPONSE[] =
334
      "HTTP/1.1 101 Switching Protocols\r\n"
335
      "Upgrade: websocket\r\n"
336
      "Connection: Upgrade\r\n"
337
12
      "Sec-WebSocket-Accept: Dt87H1OULVZnSJo/KgMUYI7xPCg=\r\n\r\n";
338
12
  expect_on_client(UPGRADE_RESPONSE, sizeof(UPGRADE_RESPONSE) - 1);
339
12
}
340
341
6
static void expect_handshake_failure() {
342
  const char UPGRADE_RESPONSE[] =
343
      "HTTP/1.0 400 Bad Request\r\n"
344
      "Content-Type: text/html; charset=UTF-8\r\n\r\n"
345
6
      "WebSockets request was expected\r\n";
346
6
  expect_on_client(UPGRADE_RESPONSE, sizeof(UPGRADE_RESPONSE) - 1);
347
6
}
348
349
20
static void on_connection(uv_connect_t* connect, int status) {
350

40
  GTEST_ASSERT_EQ(0, status);
351
20
  connect->data = connect;
352
}
353
354
40
class InspectorSocketTest : public ::testing::Test {
355
 protected:
356
20
  virtual void SetUp() {
357
20
    connected = false;
358

20
    GTEST_ASSERT_EQ(0, uv_loop_init(&loop));
359
20
    server = uv_tcp_t();
360
20
    client_socket = uv_tcp_t();
361
    sockaddr_in addr;
362
20
    uv_tcp_init(&loop, &server);
363
20
    uv_tcp_init(&loop, &client_socket);
364

20
    GTEST_ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", PORT, &addr));
365
20
    uv_tcp_bind(&server, reinterpret_cast<const struct sockaddr*>(&addr), 0);
366

20
    GTEST_ASSERT_EQ(0, uv_listen(reinterpret_cast<uv_stream_t*>(&server),
367
20
                                 1, on_new_connection));
368
    uv_connect_t connect;
369
20
    connect.data = nullptr;
370

20
    GTEST_ASSERT_EQ(0, uv_tcp_connect(&connect, &client_socket,
371
                                      reinterpret_cast<const sockaddr*>(&addr),
372
20
                                      on_connection));
373
20
    uv_tcp_nodelay(&client_socket, 1);  // The buffering messes up the test
374




20
    SPIN_WHILE(!connect.data || !connected);
375
20
    really_close(reinterpret_cast<uv_handle_t*>(&server));
376
  }
377
378
20
  virtual void TearDown() {
379
20
    really_close(reinterpret_cast<uv_handle_t*>(&client_socket));
380


40
    SPIN_WHILE(delegate != nullptr);
381
20
    const int err = uv_loop_close(&loop);
382
20
    if (err != 0) {
383
      uv_print_all_handles(&loop, stderr);
384
    }
385
20
    EXPECT_EQ(0, err);
386
  }
387
};
388
389
5
TEST_F(InspectorSocketTest, ReadsAndWritesInspectorMessage) {
390

1
  ASSERT_TRUE(connected);
391

1
  ASSERT_FALSE(delegate->inspector_ready);
392
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
393


1
  SPIN_WHILE(!delegate->inspector_ready);
394
1
  expect_handshake();
395
396
  // 2. Brief exchange
397
1
  const char SERVER_MESSAGE[] = "abcd";
398
1
  const char CLIENT_FRAME[] = {'\x81', '\x04', 'a', 'b', 'c', 'd'};
399
1
  delegate->Write(SERVER_MESSAGE, sizeof(SERVER_MESSAGE) - 1);
400
1
  expect_on_client(CLIENT_FRAME, sizeof(CLIENT_FRAME));
401
402
  const char SERVER_FRAME[] = {'\x81', '\x84', '\x7F', '\xC2', '\x66',
403
1
                               '\x31', '\x4E', '\xF0', '\x55', '\x05'};
404
1
  const char CLIENT_MESSAGE[] = "1234";
405
1
  do_write(SERVER_FRAME, sizeof(SERVER_FRAME));
406
1
  delegate->ExpectData(CLIENT_MESSAGE, sizeof(CLIENT_MESSAGE) - 1);
407
408
  // 3. Close
409
  const char CLIENT_CLOSE_FRAME[] = {'\x88', '\x80', '\x2D',
410
1
                                     '\x0E', '\x1E', '\xFA'};
411
1
  const char SERVER_CLOSE_FRAME[] = {'\x88', '\x00'};
412
1
  do_write(CLIENT_CLOSE_FRAME, sizeof(CLIENT_CLOSE_FRAME));
413
1
  expect_on_client(SERVER_CLOSE_FRAME, sizeof(SERVER_CLOSE_FRAME));
414

1
  GTEST_ASSERT_EQ(0, uv_is_active(
415
1
                         reinterpret_cast<uv_handle_t*>(&client_socket)));
416
}
417
418
5
TEST_F(InspectorSocketTest, BufferEdgeCases) {
419
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
420
1
  expect_handshake();
421
422
  const char MULTIPLE_REQUESTS[] = {
423
      '\x81', '\xCB', '\x76', '\xCA', '\x06', '\x0C', '\x0D', '\xE8', '\x6F',
424
      '\x68', '\x54', '\xF0', '\x37', '\x3E', '\x5A', '\xE8', '\x6B', '\x69',
425
      '\x02', '\xA2', '\x69', '\x68', '\x54', '\xF0', '\x24', '\x5B', '\x19',
426
      '\xB8', '\x6D', '\x69', '\x04', '\xE4', '\x75', '\x69', '\x02', '\x8B',
427
      '\x73', '\x78', '\x19', '\xA9', '\x69', '\x62', '\x18', '\xAF', '\x65',
428
      '\x78', '\x22', '\xA5', '\x51', '\x63', '\x04', '\xA1', '\x63', '\x7E',
429
      '\x05', '\xE8', '\x2A', '\x2E', '\x06', '\xAB', '\x74', '\x6D', '\x1B',
430
      '\xB9', '\x24', '\x36', '\x0D', '\xE8', '\x70', '\x6D', '\x1A', '\xBF',
431
      '\x63', '\x2E', '\x4C', '\xBE', '\x74', '\x79', '\x13', '\xB7', '\x7B',
432
      '\x81', '\xA2', '\xFC', '\x9E', '\x0D', '\x15', '\x87', '\xBC', '\x64',
433
      '\x71', '\xDE', '\xA4', '\x3C', '\x26', '\xD0', '\xBC', '\x60', '\x70',
434
      '\x88', '\xF6', '\x62', '\x71', '\xDE', '\xA4', '\x2F', '\x42', '\x93',
435
      '\xEC', '\x66', '\x70', '\x8E', '\xB0', '\x68', '\x7B', '\x9D', '\xFC',
436
      '\x61', '\x70', '\xDE', '\xE3', '\x81', '\xA4', '\x4E', '\x37', '\xB0',
437
      '\x22', '\x35', '\x15', '\xD9', '\x46', '\x6C', '\x0D', '\x81', '\x16',
438
      '\x62', '\x15', '\xDD', '\x47', '\x3A', '\x5F', '\xDF', '\x46', '\x6C',
439
      '\x0D', '\x92', '\x72', '\x3C', '\x58', '\xD6', '\x4B', '\x22', '\x52',
440
      '\xC2', '\x0C', '\x2B', '\x59', '\xD1', '\x40', '\x22', '\x52', '\x92',
441
      '\x5F', '\x81', '\xCB', '\xCD', '\xF0', '\x30', '\xC5', '\xB6', '\xD2',
442
      '\x59', '\xA1', '\xEF', '\xCA', '\x01', '\xF0', '\xE1', '\xD2', '\x5D',
443
      '\xA0', '\xB9', '\x98', '\x5F', '\xA1', '\xEF', '\xCA', '\x12', '\x95',
444
      '\xBF', '\x9F', '\x56', '\xAC', '\xA1', '\x95', '\x42', '\xEB', '\xBE',
445
      '\x95', '\x44', '\x96', '\xAC', '\x9D', '\x40', '\xA9', '\xA4', '\x9E',
446
      '\x57', '\x8C', '\xA3', '\x84', '\x55', '\xB7', '\xBB', '\x91', '\x5C',
447
      '\xE7', '\xE1', '\xD2', '\x40', '\xA4', '\xBF', '\x91', '\x5D', '\xB6',
448
      '\xEF', '\xCA', '\x4B', '\xE7', '\xA4', '\x9E', '\x44', '\xA0', '\xBF',
449
      '\x86', '\x51', '\xA9', '\xEF', '\xCA', '\x01', '\xF5', '\xFD', '\x8D',
450
      '\x4D', '\x81', '\xA9', '\x74', '\x6B', '\x72', '\x43', '\x0F', '\x49',
451
      '\x1B', '\x27', '\x56', '\x51', '\x43', '\x75', '\x58', '\x49', '\x1F',
452
      '\x26', '\x00', '\x03', '\x1D', '\x27', '\x56', '\x51', '\x50', '\x10',
453
      '\x11', '\x19', '\x04', '\x2A', '\x17', '\x0E', '\x25', '\x2C', '\x06',
454
      '\x00', '\x17', '\x31', '\x5A', '\x0E', '\x1C', '\x22', '\x16', '\x07',
455
      '\x17', '\x61', '\x09', '\x81', '\xB8', '\x7C', '\x1A', '\xEA', '\xEB',
456
      '\x07', '\x38', '\x83', '\x8F', '\x5E', '\x20', '\xDB', '\xDC', '\x50',
457
      '\x38', '\x87', '\x8E', '\x08', '\x72', '\x85', '\x8F', '\x5E', '\x20',
458
      '\xC8', '\xA5', '\x19', '\x6E', '\x9D', '\x84', '\x0E', '\x71', '\xC4',
459
      '\x88', '\x1D', '\x74', '\xAF', '\x86', '\x09', '\x76', '\x8B', '\x9F',
460
      '\x19', '\x54', '\x8F', '\x9F', '\x0B', '\x75', '\x98', '\x80', '\x3F',
461
      '\x75', '\x84', '\x8F', '\x15', '\x6E', '\x83', '\x84', '\x12', '\x69',
462
1
      '\xC8', '\x96'};
463
464
  const char EXPECT[] = {
465
      "{\"id\":12,\"method\":\"Worker.setAutoconnectToWorkers\","
466
      "\"params\":{\"value\":true}}"
467
      "{\"id\":13,\"method\":\"Worker.enable\"}"
468
      "{\"id\":14,\"method\":\"Profiler.enable\"}"
469
      "{\"id\":15,\"method\":\"Profiler.setSamplingInterval\","
470
      "\"params\":{\"interval\":100}}"
471
      "{\"id\":16,\"method\":\"ServiceWorker.enable\"}"
472
1
      "{\"id\":17,\"method\":\"Network.canEmulateNetworkConditions\"}"};
473
474
1
  do_write(MULTIPLE_REQUESTS, sizeof(MULTIPLE_REQUESTS));
475
1
  delegate->ExpectData(EXPECT, sizeof(EXPECT) - 1);
476
1
}
477
478
5
TEST_F(InspectorSocketTest, AcceptsRequestInSeveralWrites) {
479

1
  ASSERT_TRUE(connected);
480

1
  ASSERT_FALSE(delegate->inspector_ready);
481
  // Specifically, break up the request in the "Sec-WebSocket-Key" header name
482
  // and value
483
1
  const int write1 = 95;
484
1
  const int write2 = 5;
485
1
  const int write3 = sizeof(HANDSHAKE_REQ) - write1 - write2 - 1;
486
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), write1);
487

1
  ASSERT_FALSE(delegate->inspector_ready);
488
1
  do_write(const_cast<char*>(HANDSHAKE_REQ) + write1, write2);
489

1
  ASSERT_FALSE(delegate->inspector_ready);
490
1
  do_write(const_cast<char*>(HANDSHAKE_REQ) + write1 + write2, write3);
491


1
  SPIN_WHILE(!delegate->inspector_ready);
492
1
  expect_handshake();
493

1
  GTEST_ASSERT_EQ(uv_is_active(reinterpret_cast<uv_handle_t*>(&client_socket)),
494
1
                  0);
495
}
496
497
5
TEST_F(InspectorSocketTest, ExtraTextBeforeRequest) {
498
1
  delegate->last_event = kInspectorHandshakeUpgraded;
499
1
  char UNCOOL_BRO[] = "Text before the first req, shouldn't be her\r\n";
500
1
  do_write(const_cast<char*>(UNCOOL_BRO), sizeof(UNCOOL_BRO) - 1);
501
1
  expect_handshake_failure();
502

1
  GTEST_ASSERT_EQ(nullptr, delegate);
503
}
504
505
5
TEST_F(InspectorSocketTest, RequestWithoutKey) {
506
  const char BROKEN_REQUEST[] = "GET / HTTP/1.1\r\n"
507
                                "Host: localhost:9229\r\n"
508
                                "Upgrade: websocket\r\n"
509
                                "Connection: Upgrade\r\n"
510
1
                                "Sec-WebSocket-Version: 13\r\n\r\n";
511
512
1
  do_write(const_cast<char*>(BROKEN_REQUEST), sizeof(BROKEN_REQUEST) - 1);
513
1
  expect_handshake_failure();
514
1
}
515
516
5
TEST_F(InspectorSocketTest, KillsConnectionOnProtocolViolation) {
517

1
  ASSERT_TRUE(connected);
518

1
  ASSERT_FALSE(delegate->inspector_ready);
519
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
520


1
  SPIN_WHILE(!delegate->inspector_ready);
521

1
  ASSERT_TRUE(delegate->inspector_ready);
522
1
  expect_handshake();
523
1
  const char SERVER_FRAME[] = "I'm not a good WS frame. Nope!";
524
1
  do_write(SERVER_FRAME, sizeof(SERVER_FRAME));
525


1
  SPIN_WHILE(delegate != nullptr);
526

1
  GTEST_ASSERT_EQ(uv_is_active(reinterpret_cast<uv_handle_t*>(&client_socket)),
527
1
                  0);
528
}
529
530
5
TEST_F(InspectorSocketTest, CanStopReadingFromInspector) {
531

1
  ASSERT_TRUE(connected);
532

1
  ASSERT_FALSE(delegate->inspector_ready);
533
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
534
1
  expect_handshake();
535

1
  ASSERT_TRUE(delegate->inspector_ready);
536
537
  // 2. Brief exchange
538
  const char SERVER_FRAME[] = {'\x81', '\x84', '\x7F', '\xC2', '\x66',
539
1
                               '\x31', '\x4E', '\xF0', '\x55', '\x05'};
540
1
  const char CLIENT_MESSAGE[] = "1234";
541
1
  do_write(SERVER_FRAME, sizeof(SERVER_FRAME));
542
1
  delegate->ExpectData(CLIENT_MESSAGE, sizeof(CLIENT_MESSAGE) - 1);
543
544
1
  do_write(SERVER_FRAME, sizeof(SERVER_FRAME));
545

1
  GTEST_ASSERT_EQ(uv_is_active(
546
1
                      reinterpret_cast<uv_handle_t*>(&client_socket)), 0);
547
}
548
549
5
TEST_F(InspectorSocketTest, CloseDoesNotNotifyReadCallback) {
550
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
551
1
  expect_handshake();
552
553
1
  delegate->Close();
554
1
  char CLOSE_FRAME[] = {'\x88', '\x00'};
555
1
  expect_on_client(CLOSE_FRAME, sizeof(CLOSE_FRAME));
556
  const char CLIENT_CLOSE_FRAME[] = {'\x88', '\x80', '\x2D',
557
1
                                     '\x0E', '\x1E', '\xFA'};
558
1
  delegate->FailOnWsFrame();
559
1
  do_write(CLIENT_CLOSE_FRAME, sizeof(CLIENT_CLOSE_FRAME));
560


1
  SPIN_WHILE(delegate != nullptr);
561
}
562
563
5
TEST_F(InspectorSocketTest, CloseWorksWithoutReadEnabled) {
564
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
565
1
  expect_handshake();
566
1
  delegate->Close();
567
1
  char CLOSE_FRAME[] = {'\x88', '\x00'};
568
1
  expect_on_client(CLOSE_FRAME, sizeof(CLOSE_FRAME));
569
  const char CLIENT_CLOSE_FRAME[] = {'\x88', '\x80', '\x2D',
570
1
                                     '\x0E', '\x1E', '\xFA'};
571
1
  do_write(CLIENT_CLOSE_FRAME, sizeof(CLIENT_CLOSE_FRAME));
572
1
}
573
574
// Make sure buffering works
575
6
static void send_in_chunks(const char* data, size_t len) {
576
6
  const int step = 7;
577
6
  size_t i = 0;
578
  // Do not send it all at once - test the buffering!
579
90
  for (; i < len - step; i += step) {
580
84
    do_write(data + i, step);
581
  }
582
6
  if (i < len) {
583
6
    do_write(data + i, len - i);
584
  }
585
6
}
586
587
static const char TEST_SUCCESS[] = "Test Success\n\n";
588
static int ReportsHttpGet_eventsCount = 0;
589
590
4
static void ReportsHttpGet_handshake(enum inspector_handshake_event state,
591
                                     const std::string& path, bool* cont) {
592
4
  *cont = true;
593
4
  enum inspector_handshake_event expected_state = kInspectorHandshakeHttpGet;
594
4
  std::string expected_path;
595

4
  switch (delegate->handshake_events) {
596
  case 1:
597
1
    expected_path = "/some/path";
598
1
    break;
599
  case 2:
600
1
    expected_path = "/respond/withtext";
601
1
    delegate->Write(TEST_SUCCESS, sizeof(TEST_SUCCESS) - 1);
602
1
    break;
603
  case 3:
604
1
    expected_path = "/some/path2";
605
1
    break;
606
  case 4:
607
1
    expected_path = "/close";
608
1
    *cont = false;
609
1
    break;
610
  default:
611

4
    ASSERT_TRUE(false);
612
  }
613
4
  EXPECT_EQ(expected_state, state);
614
4
  EXPECT_EQ(expected_path, path);
615
4
  ReportsHttpGet_eventsCount = delegate->handshake_events;
616
}
617
618
5
TEST_F(InspectorSocketTest, ReportsHttpGet) {
619
1
  delegate->SetDelegate(ReportsHttpGet_handshake);
620
621
  const char GET_REQ[] = "GET /some/path HTTP/1.1\r\n"
622
                         "Host: localhost:9229\r\n"
623
                         "Sec-WebSocket-Key: aaa==\r\n"
624
1
                         "Sec-WebSocket-Version: 13\r\n\r\n";
625
1
  send_in_chunks(GET_REQ, sizeof(GET_REQ) - 1);
626
627
1
  expect_nothing_on_client();
628
  const char WRITE_REQUEST[] = "GET /respond/withtext HTTP/1.1\r\n"
629
1
                               "Host: localhost:9229\r\n\r\n";
630
1
  send_in_chunks(WRITE_REQUEST, sizeof(WRITE_REQUEST) - 1);
631
632
1
  expect_on_client(TEST_SUCCESS, sizeof(TEST_SUCCESS) - 1);
633
  const char GET_REQS[] = "GET /some/path2 HTTP/1.1\r\n"
634
                          "Host: localhost:9229\r\n"
635
                          "Sec-WebSocket-Key: aaa==\r\n"
636
                          "Sec-WebSocket-Version: 13\r\n\r\n"
637
                          "GET /close HTTP/1.1\r\n"
638
                          "Host: localhost:9229\r\n"
639
                          "Sec-WebSocket-Key: aaa==\r\n"
640
1
                          "Sec-WebSocket-Version: 13\r\n\r\n";
641
1
  send_in_chunks(GET_REQS, sizeof(GET_REQS) - 1);
642
1
  expect_handshake_failure();
643
1
  EXPECT_EQ(4, ReportsHttpGet_eventsCount);
644
1
  EXPECT_EQ(nullptr, delegate);
645
1
}
646
647
static int HandshakeCanBeCanceled_eventCount = 0;
648
649
static
650
1
void HandshakeCanBeCanceled_handshake(enum inspector_handshake_event state,
651
                                      const std::string& path, bool* cont) {
652
1
  switch (delegate->handshake_events - 1) {
653
  case 0:
654
1
    EXPECT_EQ(kInspectorHandshakeUpgraded, state);
655
1
    EXPECT_EQ("/ws/path", path);
656
1
    break;
657
  default:
658
    EXPECT_TRUE(false);
659
    break;
660
  }
661
1
  *cont = false;
662
1
  HandshakeCanBeCanceled_eventCount = delegate->handshake_events;
663
1
}
664
665
5
TEST_F(InspectorSocketTest, HandshakeCanBeCanceled) {
666
1
  delegate->SetDelegate(HandshakeCanBeCanceled_handshake);
667
668
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
669
670
1
  expect_handshake_failure();
671
1
  EXPECT_EQ(1, HandshakeCanBeCanceled_eventCount);
672
1
  EXPECT_EQ(nullptr, delegate);
673
1
}
674
675
2
static void GetThenHandshake_handshake(enum inspector_handshake_event state,
676
                                       const std::string& path, bool* cont) {
677
2
  *cont = true;
678
2
  std::string expected_path = "/ws/path";
679
2
  switch (delegate->handshake_events - 1) {
680
  case 0:
681
1
    EXPECT_EQ(kInspectorHandshakeHttpGet, state);
682
1
    expected_path = "/respond/withtext";
683
1
    delegate->Write(TEST_SUCCESS, sizeof(TEST_SUCCESS) - 1);
684
1
    break;
685
  case 1:
686
1
    EXPECT_EQ(kInspectorHandshakeUpgraded, state);
687
1
    break;
688
  default:
689
    EXPECT_TRUE(false);
690
    break;
691
  }
692
2
  EXPECT_EQ(expected_path, path);
693
2
}
694
695
5
TEST_F(InspectorSocketTest, GetThenHandshake) {
696
1
  delegate->SetDelegate(GetThenHandshake_handshake);
697
  const char WRITE_REQUEST[] = "GET /respond/withtext HTTP/1.1\r\n"
698
1
                               "Host: localhost:9229\r\n\r\n";
699
1
  send_in_chunks(WRITE_REQUEST, sizeof(WRITE_REQUEST) - 1);
700
701
1
  expect_on_client(TEST_SUCCESS, sizeof(TEST_SUCCESS) - 1);
702
703
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
704
1
  expect_handshake();
705
1
  EXPECT_EQ(2, delegate->handshake_events);
706
1
}
707
708
5
TEST_F(InspectorSocketTest, WriteBeforeHandshake) {
709
1
  const char MESSAGE1[] = "Message 1";
710
1
  const char MESSAGE2[] = "Message 2";
711
1
  const char EXPECTED[] = "Message 1Message 2";
712
713
1
  delegate->Write(MESSAGE1, sizeof(MESSAGE1) - 1);
714
1
  delegate->Write(MESSAGE2, sizeof(MESSAGE2) - 1);
715
1
  expect_on_client(EXPECTED, sizeof(EXPECTED) - 1);
716
1
  really_close(reinterpret_cast<uv_handle_t*>(&client_socket));
717


1
  SPIN_WHILE(delegate != nullptr);
718
}
719
720
5
TEST_F(InspectorSocketTest, CleanupSocketAfterEOF) {
721
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
722
1
  expect_handshake();
723
724
10001
  for (int i = 0; i < MAX_LOOP_ITERATIONS; ++i) {
725
10000
    uv_run(&loop, UV_RUN_NOWAIT);
726
  }
727
728
1
  uv_close(reinterpret_cast<uv_handle_t*>(&client_socket), nullptr);
729


1
  SPIN_WHILE(delegate != nullptr);
730
}
731
732
5
TEST_F(InspectorSocketTest, EOFBeforeHandshake) {
733
1
  const char MESSAGE[] = "We'll send EOF afterwards";
734
1
  delegate->Write(MESSAGE, sizeof(MESSAGE) - 1);
735
1
  expect_on_client(MESSAGE, sizeof(MESSAGE) - 1);
736
1
  uv_close(reinterpret_cast<uv_handle_t*>(&client_socket), nullptr);
737


1
  SPIN_WHILE(delegate != nullptr);
738
}
739
740
1
static void fill_message(std::string* buffer) {
741
1000001
  for (size_t i = 0; i < buffer->size(); i += 1) {
742
1000000
    (*buffer)[i] = 'a' + (i % ('z' - 'a'));
743
  }
744
1
}
745
746
1
static void mask_message(const std::string& message,
747
                         char* buffer, const char mask[]) {
748
1
  const size_t mask_len = 4;
749
1000001
  for (size_t i = 0; i < message.size(); i += 1) {
750
1000000
    buffer[i] = message[i] ^ mask[i % mask_len];
751
  }
752
1
}
753
754
5
TEST_F(InspectorSocketTest, Send1Mb) {
755

1
  ASSERT_TRUE(connected);
756

1
  ASSERT_FALSE(delegate->inspector_ready);
757
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
758


1
  SPIN_WHILE(!delegate->inspector_ready);
759
1
  expect_handshake();
760
761
  // 2. Brief exchange
762
1
  std::string message(1000000, '\0');
763
1
  fill_message(&message);
764
765
  // 1000000 is 0xF4240 hex
766
  const char EXPECTED_FRAME_HEADER[] = {
767
    '\x81', '\x7f', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0F',
768
    '\x42', '\x40'
769
1
  };
770
2
  std::string expected(EXPECTED_FRAME_HEADER, sizeof(EXPECTED_FRAME_HEADER));
771
1
  expected.append(message);
772
773
1
  delegate->Write(&message[0], message.size());
774
1
  expect_on_client(&expected[0], expected.size());
775
776
1
  char MASK[4] = {'W', 'h', 'O', 'a'};
777
778
  const char FRAME_TO_SERVER_HEADER[] = {
779
    '\x81', '\xff', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0F',
780
4
    '\x42', '\x40', MASK[0], MASK[1], MASK[2], MASK[3]
781
5
  };
782
783
2
  std::string outgoing(FRAME_TO_SERVER_HEADER, sizeof(FRAME_TO_SERVER_HEADER));
784
1
  outgoing.resize(outgoing.size() + message.size());
785
1
  mask_message(message, &outgoing[sizeof(FRAME_TO_SERVER_HEADER)], MASK);
786
787
1
  do_write(&outgoing[0], outgoing.size());
788
1
  delegate->ExpectData(&message[0], message.size());
789
790
  // 3. Close
791
  const char CLIENT_CLOSE_FRAME[] = {'\x88', '\x80', '\x2D',
792
1
                                     '\x0E', '\x1E', '\xFA'};
793
1
  do_write(CLIENT_CLOSE_FRAME, sizeof(CLIENT_CLOSE_FRAME));
794
1
  expect_on_client(SERVER_CLOSE_FRAME, sizeof(SERVER_CLOSE_FRAME));
795

1
  GTEST_ASSERT_EQ(0, uv_is_active(
796
2
                         reinterpret_cast<uv_handle_t*>(&client_socket)));
797
}
798
799
5
TEST_F(InspectorSocketTest, ErrorCleansUpTheSocket) {
800
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
801
1
  expect_handshake();
802
1
  const char NOT_A_GOOD_FRAME[] = {'H', 'e', 'l', 'l', 'o'};
803
1
  do_write(NOT_A_GOOD_FRAME, sizeof(NOT_A_GOOD_FRAME));
804


1
  SPIN_WHILE(delegate != nullptr);
805
}
806
807
5
TEST_F(InspectorSocketTest, NoCloseResponseFromClient) {
808

1
  ASSERT_TRUE(connected);
809

1
  ASSERT_FALSE(delegate->inspector_ready);
810
1
  do_write(const_cast<char*>(HANDSHAKE_REQ), sizeof(HANDSHAKE_REQ) - 1);
811


1
  SPIN_WHILE(!delegate->inspector_ready);
812
1
  expect_handshake();
813
814
  // 2. Brief exchange
815
1
  const char SERVER_MESSAGE[] = "abcd";
816
1
  const char CLIENT_FRAME[] = {'\x81', '\x04', 'a', 'b', 'c', 'd'};
817
1
  delegate->Write(SERVER_MESSAGE, sizeof(SERVER_MESSAGE) - 1);
818
1
  expect_on_client(CLIENT_FRAME, sizeof(CLIENT_FRAME));
819
820
1
  delegate->Close();
821
1
  expect_on_client(SERVER_CLOSE_FRAME, sizeof(SERVER_CLOSE_FRAME));
822
1
  uv_close(reinterpret_cast<uv_handle_t*>(&client_socket), nullptr);
823

1
  GTEST_ASSERT_EQ(0, uv_is_active(
824
1
                  reinterpret_cast<uv_handle_t*>(&client_socket)));
825
1
  delegate->WaitForDispose();
826
}
827
828
static bool delegate_called = false;
829
830
void shouldnt_be_called(enum inspector_handshake_event state,
831
                        const std::string& path, bool* cont) {
832
  delegate_called = true;
833
}
834
835
2
void expect_failure_no_delegate(const std::string& request) {
836
2
  delegate->SetDelegate(shouldnt_be_called);
837
2
  delegate_called = false;
838
2
  send_in_chunks(request.c_str(), request.length());
839
2
  expect_handshake_failure();
840


2
  SPIN_WHILE(delegate != nullptr);
841

2
  ASSERT_FALSE(delegate_called);
842
}
843
844
5
TEST_F(InspectorSocketTest, HostCheckedForGET) {
845
  const char GET_REQUEST[] = "GET /respond/withtext HTTP/1.1\r\n"
846
1
                             "Host: notlocalhost:9229\r\n\r\n";
847
1
  expect_failure_no_delegate(GET_REQUEST);
848
1
}
849
850
5
TEST_F(InspectorSocketTest, HostCheckedForUPGRADE) {
851
  const char UPGRADE_REQUEST[] = "GET /ws/path HTTP/1.1\r\n"
852
                                 "Host: nonlocalhost:9229\r\n"
853
                                 "Upgrade: websocket\r\n"
854
                                 "Connection: Upgrade\r\n"
855
                                 "Sec-WebSocket-Key: aaa==\r\n"
856
1
                                 "Sec-WebSocket-Version: 13\r\n\r\n";
857
1
  expect_failure_no_delegate(UPGRADE_REQUEST);
858
1
}
859
860

3
}  // anonymous namespace