1 #include "inspector_socket_server.h"
2
3 #include "node.h"
4 #include "node_options.h"
5 #include "util-inl.h"
6 #include "gtest/gtest.h"
7
8 #include <algorithm>
9 #include <memory>
10 #include <sstream>
11
12 static uv_loop_t loop;
13
14 static const char HOST[] = "127.0.0.1";
15
16 static const char CLIENT_CLOSE_FRAME[] = "\x88\x80\x2D\x0E\x1E\xFA";
17 static const char SERVER_CLOSE_FRAME[] = "\x88\x00";
18
19 static const char MAIN_TARGET_ID[] = "main-target";
20
21 static const char WS_HANDSHAKE_RESPONSE[] =
22 "HTTP/1.1 101 Switching Protocols\r\n"
23 "Upgrade: websocket\r\n"
24 "Connection: Upgrade\r\n"
25 "Sec-WebSocket-Accept: Dt87H1OULVZnSJo/KgMUYI7xPCg=\r\n\r\n";
26
27 #define SPIN_WHILE(condition) \
28 { \
29 Timeout timeout(&loop); \
30 while ((condition) && !timeout.timed_out) { \
31 uv_run(&loop, UV_RUN_ONCE); \
32 } \
33 ASSERT_FALSE((condition)); \
34 }
35
36 namespace {
37
38 using InspectorSocketServer = node::inspector::InspectorSocketServer;
39 using SocketServerDelegate = node::inspector::SocketServerDelegate;
40
41 class Timeout {
42 public:
Timeout(uv_loop_t * loop)43 explicit Timeout(uv_loop_t* loop) : timed_out(false), done_(false) {
44 uv_timer_init(loop, &timer_);
45 uv_timer_start(&timer_, Timeout::set_flag, 5000, 0);
46 uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
47 }
48
~Timeout()49 ~Timeout() {
50 uv_timer_stop(&timer_);
51 uv_close(reinterpret_cast<uv_handle_t*>(&timer_), mark_done);
52 while (!done_) {
53 uv_run(&loop, UV_RUN_NOWAIT);
54 }
55 }
56 bool timed_out;
57
58 private:
set_flag(uv_timer_t * timer)59 static void set_flag(uv_timer_t* timer) {
60 Timeout* t = node::ContainerOf(&Timeout::timer_, timer);
61 t->timed_out = true;
62 }
63
mark_done(uv_handle_t * timer)64 static void mark_done(uv_handle_t* timer) {
65 Timeout* t = node::ContainerOf(&Timeout::timer_,
66 reinterpret_cast<uv_timer_t*>(timer));
67 t->done_ = true;
68 }
69
70 bool done_;
71 uv_timer_t timer_;
72 };
73
74 class InspectorSocketServerTest : public ::testing::Test {
75 protected:
SetUp()76 void SetUp() override {
77 EXPECT_EQ(0, uv_loop_init(&loop));
78 }
79
TearDown()80 void TearDown() override {
81 const int err = uv_loop_close(&loop);
82 if (err != 0) {
83 uv_print_all_handles(&loop, stderr);
84 }
85 EXPECT_EQ(0, err);
86 }
87 };
88
89 class SocketWrapper {
90 public:
SocketWrapper(uv_loop_t * loop)91 explicit SocketWrapper(uv_loop_t* loop) : closed_(false),
92 eof_(false),
93 loop_(loop),
94 socket_(uv_tcp_t()),
95 connected_(false),
96 sending_(false) { }
97
Connect(const std::string & host,int port,bool v6=false)98 void Connect(const std::string& host, int port, bool v6 = false) {
99 closed_ = false;
100 connection_failed_ = false;
101 connected_ = false;
102 eof_ = false;
103 contents_.clear();
104 uv_tcp_init(loop_, &socket_);
105 union {sockaddr generic; sockaddr_in v4; sockaddr_in6 v6;} addr;
106 int err = 0;
107 if (v6) {
108 err = uv_ip6_addr(host.c_str(), port, &addr.v6);
109 } else {
110 err = uv_ip4_addr(host.c_str(), port, &addr.v4);
111 }
112 CHECK_EQ(0, err);
113 err = uv_tcp_connect(&connect_, &socket_, &addr.generic, Connected_);
114 CHECK_EQ(0, err);
115 SPIN_WHILE(!connected_)
116 uv_read_start(reinterpret_cast<uv_stream_t*>(&socket_), AllocCallback,
117 ReadCallback);
118 }
119
ExpectFailureToConnect(const std::string & host,int port)120 void ExpectFailureToConnect(const std::string& host, int port) {
121 connected_ = false;
122 connection_failed_ = false;
123 closed_ = false;
124 eof_ = false;
125 contents_.clear();
126 uv_tcp_init(loop_, &socket_);
127 sockaddr_in addr;
128 int err = uv_ip4_addr(host.c_str(), port, &addr);
129 CHECK_EQ(0, err);
130 err = uv_tcp_connect(&connect_, &socket_,
131 reinterpret_cast<const sockaddr*>(&addr),
132 ConnectionMustFail_);
133 CHECK_EQ(0, err);
134 SPIN_WHILE(!connection_failed_)
135 uv_read_start(reinterpret_cast<uv_stream_t*>(&socket_), AllocCallback,
136 ReadCallback);
137 }
138
Close()139 void Close() {
140 uv_close(reinterpret_cast<uv_handle_t*>(&socket_), ClosedCallback);
141 SPIN_WHILE(!closed_);
142 }
143
Expect(const std::string & expects)144 void Expect(const std::string& expects) {
145 SPIN_WHILE(contents_.size() < expects.length());
146 ASSERT_STREQ(expects.c_str(),
147 std::string(contents_.data(), expects.length()).c_str());
148 contents_.erase(contents_.begin(), contents_.begin() + expects.length());
149 }
150
ExpectEOF()151 void ExpectEOF() {
152 SPIN_WHILE(!eof_);
153 Close();
154 }
155
TestHttpRequest(const std::string & path,const std::string & expected_reply)156 void TestHttpRequest(const std::string& path,
157 const std::string& expected_reply) {
158 std::ostringstream expectations;
159 expectations << "HTTP/1.0 200 OK\r\n"
160 "Content-Type: application/json; charset=UTF-8\r\n"
161 "Cache-Control: no-cache\r\n"
162 "Content-Length: ";
163 expectations << expected_reply.length() + 2;
164 expectations << "\r\n\r\n" << expected_reply << "\n\n";
165 Write("GET " + path + " HTTP/1.1\r\n"
166 "Host: localhost:9229\r\n\r\n");
167 Expect(expectations.str());
168 }
169
Write(const std::string & data)170 void Write(const std::string& data) {
171 ASSERT_FALSE(sending_);
172 uv_buf_t buf[1];
173 buf[0].base = const_cast<char*>(data.data());
174 buf[0].len = data.length();
175 sending_ = true;
176 int err = uv_write(&write_, reinterpret_cast<uv_stream_t*>(&socket_),
177 buf, 1, WriteDone_);
178 CHECK_EQ(err, 0);
179 SPIN_WHILE(sending_);
180 }
181
182 private:
AllocCallback(uv_handle_t *,size_t size,uv_buf_t * buf)183 static void AllocCallback(uv_handle_t*, size_t size, uv_buf_t* buf) {
184 *buf = uv_buf_init(new char[size], size);
185 }
186
ClosedCallback(uv_handle_t * handle)187 static void ClosedCallback(uv_handle_t* handle) {
188 SocketWrapper* wrapper =
189 node::ContainerOf(&SocketWrapper::socket_,
190 reinterpret_cast<uv_tcp_t*>(handle));
191 ASSERT_FALSE(wrapper->closed_);
192 wrapper->closed_ = true;
193 }
194
Connected_(uv_connect_t * connect,int status)195 static void Connected_(uv_connect_t* connect, int status) {
196 EXPECT_EQ(0, status) << "Unable to connect: " << uv_strerror(status);
197 SocketWrapper* wrapper =
198 node::ContainerOf(&SocketWrapper::connect_, connect);
199 wrapper->connected_ = true;
200 }
201
ConnectionMustFail_(uv_connect_t * connect,int status)202 static void ConnectionMustFail_(uv_connect_t* connect, int status) {
203 EXPECT_EQ(UV_ECONNREFUSED, status);
204 SocketWrapper* wrapper =
205 node::ContainerOf(&SocketWrapper::connect_, connect);
206 wrapper->connection_failed_ = true;
207 }
208
ReadCallback(uv_stream_t * stream,ssize_t read,const uv_buf_t * buf)209 static void ReadCallback(uv_stream_t* stream, ssize_t read,
210 const uv_buf_t* buf) {
211 SocketWrapper* wrapper =
212 node::ContainerOf(&SocketWrapper::socket_,
213 reinterpret_cast<uv_tcp_t*>(stream));
214 if (read == UV_EOF) {
215 wrapper->eof_ = true;
216 } else {
217 wrapper->contents_.insert(wrapper->contents_.end(), buf->base,
218 buf->base + read);
219 }
220 delete[] buf->base;
221 }
WriteDone_(uv_write_t * req,int err)222 static void WriteDone_(uv_write_t* req, int err) {
223 CHECK_EQ(0, err);
224 SocketWrapper* wrapper =
225 node::ContainerOf(&SocketWrapper::write_, req);
226 ASSERT_TRUE(wrapper->sending_);
227 wrapper->sending_ = false;
228 }
IsConnected()229 bool IsConnected() { return connected_; }
230
231 bool closed_;
232 bool eof_;
233 uv_loop_t* loop_;
234 uv_tcp_t socket_;
235 uv_connect_t connect_;
236 uv_write_t write_;
237 bool connected_;
238 bool connection_failed_;
239 bool sending_;
240 std::vector<char> contents_;
241 };
242
243 class ServerHolder {
244 public:
ServerHolder(bool has_targets,uv_loop_t * loop,int port)245 ServerHolder(bool has_targets, uv_loop_t* loop, int port)
246 : ServerHolder(has_targets, loop, HOST, port, nullptr) { }
247
248 ServerHolder(bool has_targets, uv_loop_t* loop,
249 const std::string& host, int port, FILE* out);
250
operator ->()251 InspectorSocketServer* operator->() {
252 return server_.get();
253 }
254
port()255 int port() {
256 return server_->Port();
257 }
258
done()259 bool done() {
260 return server_->done();
261 }
262
Disconnected()263 void Disconnected() {
264 disconnected++;
265 }
266
Done()267 void Done() {
268 delegate_done = true;
269 }
270
Connected(int id)271 void Connected(int id) {
272 buffer_.clear();
273 session_id_ = id;
274 connected++;
275 }
276
Received(const std::string & message)277 void Received(const std::string& message) {
278 buffer_.insert(buffer_.end(), message.begin(), message.end());
279 }
280
Write(const std::string & message)281 void Write(const std::string& message) {
282 server_->Send(session_id_, message);
283 }
284
Expect(const std::string & expects)285 void Expect(const std::string& expects) {
286 SPIN_WHILE(buffer_.size() < expects.length());
287 ASSERT_STREQ(std::string(buffer_.data(), expects.length()).c_str(),
288 expects.c_str());
289 buffer_.erase(buffer_.begin(), buffer_.begin() + expects.length());
290 }
291
292 int connected = 0;
293 int disconnected = 0;
294 bool delegate_done = false;
295
296 private:
297 std::unique_ptr<InspectorSocketServer> server_;
298 std::vector<char> buffer_;
299 int session_id_;
300 };
301
302 class TestSocketServerDelegate : public SocketServerDelegate {
303 public:
TestSocketServerDelegate(ServerHolder * server,const std::vector<std::string> & target_ids)304 explicit TestSocketServerDelegate(
305 ServerHolder* server,
306 const std::vector<std::string>& target_ids)
307 : harness_(server),
308 targets_(target_ids),
309 session_id_(0) {}
310
~TestSocketServerDelegate()311 ~TestSocketServerDelegate() override {
312 harness_->Done();
313 }
314
AssignServer(InspectorSocketServer * server)315 void AssignServer(InspectorSocketServer* server) override {
316 server_ = server;
317 }
318
StartSession(int session_id,const std::string & target_id)319 void StartSession(int session_id, const std::string& target_id) override {
320 session_id_ = session_id;
321 CHECK_NE(targets_.end(),
322 std::find(targets_.begin(), targets_.end(), target_id));
323 harness_->Connected(session_id_);
324 }
325
MessageReceived(int session_id,const std::string & message)326 void MessageReceived(int session_id, const std::string& message) override {
327 CHECK_EQ(session_id_, session_id);
328 harness_->Received(message);
329 }
330
EndSession(int session_id)331 void EndSession(int session_id) override {
332 CHECK_EQ(session_id_, session_id);
333 harness_->Disconnected();
334 }
335
GetTargetIds()336 std::vector<std::string> GetTargetIds() override {
337 return targets_;
338 }
339
GetTargetTitle(const std::string & id)340 std::string GetTargetTitle(const std::string& id) override {
341 return id + " Target Title";
342 }
343
GetTargetUrl(const std::string & id)344 std::string GetTargetUrl(const std::string& id) override {
345 return "file://" + id + "/script.js";
346 }
347
348 private:
349 ServerHolder* harness_;
350 const std::vector<std::string> targets_;
351 InspectorSocketServer* server_;
352 int session_id_;
353 };
354
ServerHolder(bool has_targets,uv_loop_t * loop,const std::string & host,int port,FILE * out)355 ServerHolder::ServerHolder(bool has_targets, uv_loop_t* loop,
356 const std::string& host, int port, FILE* out) {
357 std::vector<std::string> targets;
358 if (has_targets)
359 targets = { MAIN_TARGET_ID };
360 std::unique_ptr<TestSocketServerDelegate> delegate(
361 new TestSocketServerDelegate(this, targets));
362 node::InspectPublishUid inspect_publish_uid;
363 inspect_publish_uid.console = true;
364 inspect_publish_uid.http = true;
365 server_ = std::make_unique<InspectorSocketServer>(
366 std::move(delegate), loop, host, port, inspect_publish_uid, out);
367 }
368
TestHttpRequest(int port,const std::string & path,const std::string & expected_body)369 static void TestHttpRequest(int port, const std::string& path,
370 const std::string& expected_body) {
371 SocketWrapper socket(&loop);
372 socket.Connect(HOST, port);
373 socket.TestHttpRequest(path, expected_body);
374 socket.Close();
375 }
376
WsHandshakeRequest(const std::string & target_id)377 static const std::string WsHandshakeRequest(const std::string& target_id) {
378 return "GET /" + target_id + " HTTP/1.1\r\n"
379 "Host: localhost:9229\r\n"
380 "Upgrade: websocket\r\n"
381 "Connection: Upgrade\r\n"
382 "Sec-WebSocket-Key: aaa==\r\n"
383 "Sec-WebSocket-Version: 13\r\n\r\n";
384 }
385 } // anonymous namespace
386
387
TEST_F(InspectorSocketServerTest,InspectorSessions)388 TEST_F(InspectorSocketServerTest, InspectorSessions) {
389 ServerHolder server(true, &loop, 0);
390 ASSERT_TRUE(server->Start());
391
392 SocketWrapper well_behaved_socket(&loop);
393 // Regular connection
394 well_behaved_socket.Connect(HOST, server.port());
395 well_behaved_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
396 well_behaved_socket.Expect(WS_HANDSHAKE_RESPONSE);
397
398 EXPECT_EQ(1, server.connected);
399
400 well_behaved_socket.Write("\x81\x84\x7F\xC2\x66\x31\x4E\xF0\x55\x05");
401
402 server.Expect("1234");
403 server.Write("5678");
404
405 well_behaved_socket.Expect("\x81\x4" "5678");
406 well_behaved_socket.Write(CLIENT_CLOSE_FRAME);
407 well_behaved_socket.Expect(SERVER_CLOSE_FRAME);
408
409 EXPECT_EQ(1, server.disconnected);
410
411 well_behaved_socket.Close();
412
413 // Bogus target - start session callback should not even be invoked
414 SocketWrapper bogus_target_socket(&loop);
415 bogus_target_socket.Connect(HOST, server.port());
416 bogus_target_socket.Write(WsHandshakeRequest("bogus_target"));
417 bogus_target_socket.Expect("HTTP/1.0 400 Bad Request");
418 bogus_target_socket.ExpectEOF();
419 EXPECT_EQ(1, server.connected);
420 EXPECT_EQ(1, server.disconnected);
421
422 // Drop connection (no proper close frames)
423 SocketWrapper dropped_connection_socket(&loop);
424 dropped_connection_socket.Connect(HOST, server.port());
425 dropped_connection_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
426 dropped_connection_socket.Expect(WS_HANDSHAKE_RESPONSE);
427
428 EXPECT_EQ(2, server.connected);
429
430 server.Write("5678");
431 dropped_connection_socket.Expect("\x81\x4" "5678");
432
433 dropped_connection_socket.Close();
434 SPIN_WHILE(server.disconnected < 2);
435
436 // Reconnect regular connection
437 SocketWrapper stays_till_termination_socket(&loop);
438 stays_till_termination_socket.Connect(HOST, server.port());
439 stays_till_termination_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
440 stays_till_termination_socket.Expect(WS_HANDSHAKE_RESPONSE);
441
442 SPIN_WHILE(3 != server.connected);
443
444 server.Write("5678");
445 stays_till_termination_socket.Expect("\x81\x4" "5678");
446
447 stays_till_termination_socket
448 .Write("\x81\x84\x7F\xC2\x66\x31\x4E\xF0\x55\x05");
449 server.Expect("1234");
450
451 server->Stop();
452 server->TerminateConnections();
453
454 stays_till_termination_socket.Write(CLIENT_CLOSE_FRAME);
455 stays_till_termination_socket.Expect(SERVER_CLOSE_FRAME);
456
457 SPIN_WHILE(3 != server.disconnected);
458 SPIN_WHILE(!server.done());
459 stays_till_termination_socket.ExpectEOF();
460 }
461
TEST_F(InspectorSocketServerTest,ServerDoesNothing)462 TEST_F(InspectorSocketServerTest, ServerDoesNothing) {
463 ServerHolder server(true, &loop, 0);
464 ASSERT_TRUE(server->Start());
465 server->Stop();
466 server->TerminateConnections();
467 SPIN_WHILE(!server.done());
468 ASSERT_TRUE(server.delegate_done);
469 SPIN_WHILE(uv_loop_alive(&loop));
470 }
471
TEST_F(InspectorSocketServerTest,ServerWithoutTargets)472 TEST_F(InspectorSocketServerTest, ServerWithoutTargets) {
473 ServerHolder server(false, &loop, 0);
474 ASSERT_TRUE(server->Start());
475 TestHttpRequest(server.port(), "/json/list", "[ ]");
476 TestHttpRequest(server.port(), "/json", "[ ]");
477
478 // Declined connection
479 SocketWrapper socket(&loop);
480 socket.Connect(HOST, server.port());
481 socket.Write(WsHandshakeRequest("any target id"));
482 socket.Expect("HTTP/1.0 400 Bad Request");
483 socket.ExpectEOF();
484 server->Stop();
485 server->TerminateConnections();
486 SPIN_WHILE(!server.done());
487 SPIN_WHILE(uv_loop_alive(&loop));
488 }
489
TEST_F(InspectorSocketServerTest,ServerCannotStart)490 TEST_F(InspectorSocketServerTest, ServerCannotStart) {
491 ServerHolder server1(false, &loop, 0);
492 ASSERT_TRUE(server1->Start());
493 ServerHolder server2(false, &loop, server1.port());
494 ASSERT_FALSE(server2->Start());
495 server1->Stop();
496 server1->TerminateConnections();
497 SPIN_WHILE(!server1.done());
498 ASSERT_TRUE(server1.delegate_done);
499 SPIN_WHILE(uv_loop_alive(&loop));
500 }
501
TEST_F(InspectorSocketServerTest,StoppingServerDoesNotKillConnections)502 TEST_F(InspectorSocketServerTest, StoppingServerDoesNotKillConnections) {
503 ServerHolder server(false, &loop, 0);
504 ASSERT_TRUE(server->Start());
505 SocketWrapper socket1(&loop);
506 socket1.Connect(HOST, server.port());
507 socket1.TestHttpRequest("/json/list", "[ ]");
508 server->Stop();
509 socket1.TestHttpRequest("/json/list", "[ ]");
510 socket1.Close();
511 uv_run(&loop, UV_RUN_DEFAULT);
512 ASSERT_TRUE(server.delegate_done);
513 }
514
TEST_F(InspectorSocketServerTest,ClosingConnectionReportsDone)515 TEST_F(InspectorSocketServerTest, ClosingConnectionReportsDone) {
516 ServerHolder server(false, &loop, 0);
517 ASSERT_TRUE(server->Start());
518 SocketWrapper socket1(&loop);
519 socket1.Connect(HOST, server.port());
520 socket1.TestHttpRequest("/json/list", "[ ]");
521 server->Stop();
522 socket1.TestHttpRequest("/json/list", "[ ]");
523 socket1.Close();
524 uv_run(&loop, UV_RUN_DEFAULT);
525 ASSERT_TRUE(server.delegate_done);
526 }
527
TEST_F(InspectorSocketServerTest,ClosingSocketReportsDone)528 TEST_F(InspectorSocketServerTest, ClosingSocketReportsDone) {
529 ServerHolder server(true, &loop, 0);
530 ASSERT_TRUE(server->Start());
531 SocketWrapper socket1(&loop);
532 socket1.Connect(HOST, server.port());
533 socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
534 socket1.Expect(WS_HANDSHAKE_RESPONSE);
535 server->Stop();
536 ASSERT_FALSE(server.delegate_done);
537 socket1.Close();
538 SPIN_WHILE(!server.delegate_done);
539 }
540
TEST_F(InspectorSocketServerTest,TerminatingSessionReportsDone)541 TEST_F(InspectorSocketServerTest, TerminatingSessionReportsDone) {
542 ServerHolder server(true, &loop, 0);
543 ASSERT_TRUE(server->Start());
544 SocketWrapper socket1(&loop);
545 socket1.Connect(HOST, server.port());
546 socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
547 socket1.Expect(WS_HANDSHAKE_RESPONSE);
548 server->Stop();
549 ASSERT_FALSE(server.delegate_done);
550 server->TerminateConnections();
551 socket1.Expect(SERVER_CLOSE_FRAME);
552 socket1.Write(CLIENT_CLOSE_FRAME);
553 socket1.ExpectEOF();
554 SPIN_WHILE(!server.delegate_done);
555 }
556
TEST_F(InspectorSocketServerTest,FailsToBindToNodejsHost)557 TEST_F(InspectorSocketServerTest, FailsToBindToNodejsHost) {
558 ServerHolder server(true, &loop, "nodejs.org", 80, nullptr);
559 ASSERT_FALSE(server->Start());
560 SPIN_WHILE(uv_loop_alive(&loop));
561 }
562
has_ipv6_address()563 bool has_ipv6_address() {
564 uv_interface_address_s* addresses = nullptr;
565 int address_count = 0;
566 int err = uv_interface_addresses(&addresses, &address_count);
567 if (err != 0) {
568 return false;
569 }
570 bool has_address = false;
571 for (int i = 0; i < address_count; i++) {
572 if (addresses[i].address.address6.sin6_family == AF_INET6) {
573 has_address = true;
574 }
575 }
576 uv_free_interface_addresses(addresses, address_count);
577 return has_address;
578 }
579
TEST_F(InspectorSocketServerTest,BindsToIpV6)580 TEST_F(InspectorSocketServerTest, BindsToIpV6) {
581 if (!has_ipv6_address()) {
582 fprintf(stderr, "No IPv6 network detected\n");
583 return;
584 }
585 ServerHolder server(true, &loop, "::", 0, nullptr);
586 ASSERT_TRUE(server->Start());
587 SocketWrapper socket1(&loop);
588 socket1.Connect("::1", server.port(), true);
589 socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
590 socket1.Expect(WS_HANDSHAKE_RESPONSE);
591 server->Stop();
592 ASSERT_FALSE(server.delegate_done);
593 socket1.Close();
594 SPIN_WHILE(!server.delegate_done);
595 }
596