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(ServerHolder* server,
305 const std::vector<std::string>& target_ids)
306 : harness_(server),
307 targets_(target_ids),
308 server_(nullptr),
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 session_id_ = 0;
358 std::vector<std::string> targets;
359 if (has_targets)
360 targets = { MAIN_TARGET_ID };
361 std::unique_ptr<TestSocketServerDelegate> delegate(
362 new TestSocketServerDelegate(this, targets));
363 node::InspectPublishUid inspect_publish_uid;
364 inspect_publish_uid.console = true;
365 inspect_publish_uid.http = true;
366 server_ = std::make_unique<InspectorSocketServer>(
367 std::move(delegate), loop, host, port, inspect_publish_uid, out);
368 }
369
TestHttpRequest(int port,const std::string & path,const std::string & expected_body)370 static void TestHttpRequest(int port, const std::string& path,
371 const std::string& expected_body) {
372 SocketWrapper socket(&loop);
373 socket.Connect(HOST, port);
374 socket.TestHttpRequest(path, expected_body);
375 socket.Close();
376 }
377
WsHandshakeRequest(const std::string & target_id)378 static const std::string WsHandshakeRequest(const std::string& target_id) {
379 return "GET /" + target_id + " HTTP/1.1\r\n"
380 "Host: localhost:9229\r\n"
381 "Upgrade: websocket\r\n"
382 "Connection: Upgrade\r\n"
383 "Sec-WebSocket-Key: aaa==\r\n"
384 "Sec-WebSocket-Version: 13\r\n\r\n";
385 }
386 } // anonymous namespace
387
388
TEST_F(InspectorSocketServerTest,InspectorSessions)389 TEST_F(InspectorSocketServerTest, InspectorSessions) {
390 ServerHolder server(true, &loop, 0);
391 ASSERT_TRUE(server->Start());
392
393 SocketWrapper well_behaved_socket(&loop);
394 // Regular connection
395 well_behaved_socket.Connect(HOST, server.port());
396 well_behaved_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
397 well_behaved_socket.Expect(WS_HANDSHAKE_RESPONSE);
398
399 EXPECT_EQ(1, server.connected);
400
401 well_behaved_socket.Write("\x81\x84\x7F\xC2\x66\x31\x4E\xF0\x55\x05");
402
403 server.Expect("1234");
404 server.Write("5678");
405
406 well_behaved_socket.Expect("\x81\x4" "5678");
407 well_behaved_socket.Write(CLIENT_CLOSE_FRAME);
408 well_behaved_socket.Expect(SERVER_CLOSE_FRAME);
409
410 EXPECT_EQ(1, server.disconnected);
411
412 well_behaved_socket.Close();
413
414 // Bogus target - start session callback should not even be invoked
415 SocketWrapper bogus_target_socket(&loop);
416 bogus_target_socket.Connect(HOST, server.port());
417 bogus_target_socket.Write(WsHandshakeRequest("bogus_target"));
418 bogus_target_socket.Expect("HTTP/1.0 400 Bad Request");
419 bogus_target_socket.ExpectEOF();
420 EXPECT_EQ(1, server.connected);
421 EXPECT_EQ(1, server.disconnected);
422
423 // Drop connection (no proper close frames)
424 SocketWrapper dropped_connection_socket(&loop);
425 dropped_connection_socket.Connect(HOST, server.port());
426 dropped_connection_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
427 dropped_connection_socket.Expect(WS_HANDSHAKE_RESPONSE);
428
429 EXPECT_EQ(2, server.connected);
430
431 server.Write("5678");
432 dropped_connection_socket.Expect("\x81\x4" "5678");
433
434 dropped_connection_socket.Close();
435 SPIN_WHILE(server.disconnected < 2);
436
437 // Reconnect regular connection
438 SocketWrapper stays_till_termination_socket(&loop);
439 stays_till_termination_socket.Connect(HOST, server.port());
440 stays_till_termination_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
441 stays_till_termination_socket.Expect(WS_HANDSHAKE_RESPONSE);
442
443 SPIN_WHILE(3 != server.connected);
444
445 server.Write("5678");
446 stays_till_termination_socket.Expect("\x81\x4" "5678");
447
448 stays_till_termination_socket
449 .Write("\x81\x84\x7F\xC2\x66\x31\x4E\xF0\x55\x05");
450 server.Expect("1234");
451
452 server->Stop();
453 server->TerminateConnections();
454
455 stays_till_termination_socket.Write(CLIENT_CLOSE_FRAME);
456 stays_till_termination_socket.Expect(SERVER_CLOSE_FRAME);
457
458 SPIN_WHILE(3 != server.disconnected);
459 SPIN_WHILE(!server.done());
460 stays_till_termination_socket.ExpectEOF();
461 }
462
TEST_F(InspectorSocketServerTest,ServerDoesNothing)463 TEST_F(InspectorSocketServerTest, ServerDoesNothing) {
464 ServerHolder server(true, &loop, 0);
465 ASSERT_TRUE(server->Start());
466 server->Stop();
467 server->TerminateConnections();
468 SPIN_WHILE(!server.done());
469 ASSERT_TRUE(server.delegate_done);
470 SPIN_WHILE(uv_loop_alive(&loop));
471 }
472
TEST_F(InspectorSocketServerTest,ServerWithoutTargets)473 TEST_F(InspectorSocketServerTest, ServerWithoutTargets) {
474 ServerHolder server(false, &loop, 0);
475 ASSERT_TRUE(server->Start());
476 TestHttpRequest(server.port(), "/json/list", "[ ]");
477 TestHttpRequest(server.port(), "/json", "[ ]");
478
479 // Declined connection
480 SocketWrapper socket(&loop);
481 socket.Connect(HOST, server.port());
482 socket.Write(WsHandshakeRequest("any target id"));
483 socket.Expect("HTTP/1.0 400 Bad Request");
484 socket.ExpectEOF();
485 server->Stop();
486 server->TerminateConnections();
487 SPIN_WHILE(!server.done());
488 SPIN_WHILE(uv_loop_alive(&loop));
489 }
490
TEST_F(InspectorSocketServerTest,ServerCannotStart)491 TEST_F(InspectorSocketServerTest, ServerCannotStart) {
492 ServerHolder server1(false, &loop, 0);
493 ASSERT_TRUE(server1->Start());
494 ServerHolder server2(false, &loop, server1.port());
495 ASSERT_FALSE(server2->Start());
496 server1->Stop();
497 server1->TerminateConnections();
498 SPIN_WHILE(!server1.done());
499 ASSERT_TRUE(server1.delegate_done);
500 SPIN_WHILE(uv_loop_alive(&loop));
501 }
502
TEST_F(InspectorSocketServerTest,StoppingServerDoesNotKillConnections)503 TEST_F(InspectorSocketServerTest, StoppingServerDoesNotKillConnections) {
504 ServerHolder server(false, &loop, 0);
505 ASSERT_TRUE(server->Start());
506 SocketWrapper socket1(&loop);
507 socket1.Connect(HOST, server.port());
508 socket1.TestHttpRequest("/json/list", "[ ]");
509 server->Stop();
510 socket1.TestHttpRequest("/json/list", "[ ]");
511 socket1.Close();
512 uv_run(&loop, UV_RUN_DEFAULT);
513 ASSERT_TRUE(server.delegate_done);
514 }
515
TEST_F(InspectorSocketServerTest,ClosingConnectionReportsDone)516 TEST_F(InspectorSocketServerTest, ClosingConnectionReportsDone) {
517 ServerHolder server(false, &loop, 0);
518 ASSERT_TRUE(server->Start());
519 SocketWrapper socket1(&loop);
520 socket1.Connect(HOST, server.port());
521 socket1.TestHttpRequest("/json/list", "[ ]");
522 server->Stop();
523 socket1.TestHttpRequest("/json/list", "[ ]");
524 socket1.Close();
525 uv_run(&loop, UV_RUN_DEFAULT);
526 ASSERT_TRUE(server.delegate_done);
527 }
528
TEST_F(InspectorSocketServerTest,ClosingSocketReportsDone)529 TEST_F(InspectorSocketServerTest, ClosingSocketReportsDone) {
530 ServerHolder server(true, &loop, 0);
531 ASSERT_TRUE(server->Start());
532 SocketWrapper socket1(&loop);
533 socket1.Connect(HOST, server.port());
534 socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
535 socket1.Expect(WS_HANDSHAKE_RESPONSE);
536 server->Stop();
537 ASSERT_FALSE(server.delegate_done);
538 socket1.Close();
539 SPIN_WHILE(!server.delegate_done);
540 }
541
TEST_F(InspectorSocketServerTest,TerminatingSessionReportsDone)542 TEST_F(InspectorSocketServerTest, TerminatingSessionReportsDone) {
543 ServerHolder server(true, &loop, 0);
544 ASSERT_TRUE(server->Start());
545 SocketWrapper socket1(&loop);
546 socket1.Connect(HOST, server.port());
547 socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
548 socket1.Expect(WS_HANDSHAKE_RESPONSE);
549 server->Stop();
550 ASSERT_FALSE(server.delegate_done);
551 server->TerminateConnections();
552 socket1.Expect(SERVER_CLOSE_FRAME);
553 socket1.Write(CLIENT_CLOSE_FRAME);
554 socket1.ExpectEOF();
555 SPIN_WHILE(!server.delegate_done);
556 }
557
TEST_F(InspectorSocketServerTest,FailsToBindToNodejsHost)558 TEST_F(InspectorSocketServerTest, FailsToBindToNodejsHost) {
559 ServerHolder server(true, &loop, "nodejs.org", 80, nullptr);
560 ASSERT_FALSE(server->Start());
561 SPIN_WHILE(uv_loop_alive(&loop));
562 }
563
has_ipv6_address()564 bool has_ipv6_address() {
565 uv_interface_address_s* addresses = nullptr;
566 int address_count = 0;
567 int err = uv_interface_addresses(&addresses, &address_count);
568 if (err != 0) {
569 return false;
570 }
571 bool has_address = false;
572 for (int i = 0; i < address_count; i++) {
573 if (addresses[i].address.address6.sin6_family == AF_INET6) {
574 has_address = true;
575 }
576 }
577 uv_free_interface_addresses(addresses, address_count);
578 return has_address;
579 }
580
TEST_F(InspectorSocketServerTest,BindsToIpV6)581 TEST_F(InspectorSocketServerTest, BindsToIpV6) {
582 if (!has_ipv6_address()) {
583 fprintf(stderr, "No IPv6 network detected\n");
584 return;
585 }
586 ServerHolder server(true, &loop, "::", 0, nullptr);
587 ASSERT_TRUE(server->Start());
588 SocketWrapper socket1(&loop);
589 socket1.Connect("::1", server.port(), true);
590 socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
591 socket1.Expect(WS_HANDSHAKE_RESPONSE);
592 server->Stop();
593 ASSERT_FALSE(server.delegate_done);
594 socket1.Close();
595 SPIN_WHILE(!server.delegate_done);
596 }
597