Skip to content

Commit 0bcad33

Browse files
eugeneotargos
authored andcommitted
inspector: report client-visible host and port
Node instance may not know the real host and port user sees when debug frontend connects through the SSH tunnel. This change fixes '/json/list' response by using the value client provided in the host header. PR-URL: #19664 Reviewed-By: Tiancheng "Timothy" Gu <[email protected]>
1 parent c5469bb commit 0bcad33

8 files changed

+85
-42
lines changed

src/inspector_socket.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -495,12 +495,12 @@ class HttpHandler : public ProtocolHandler {
495495
CancelHandshake();
496496
return;
497497
} else if (!event.upgrade) {
498-
delegate()->OnHttpGet(event.path);
498+
delegate()->OnHttpGet(event.host, event.path);
499499
} else if (event.ws_key.empty()) {
500500
CancelHandshake();
501501
return;
502502
} else {
503-
delegate()->OnSocketUpgrade(event.path, event.ws_key);
503+
delegate()->OnSocketUpgrade(event.host, event.path, event.ws_key);
504504
}
505505
}
506506
}

src/inspector_socket.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ class InspectorSocket {
1717
public:
1818
class Delegate {
1919
public:
20-
virtual void OnHttpGet(const std::string& path) = 0;
21-
virtual void OnSocketUpgrade(const std::string& path,
20+
virtual void OnHttpGet(const std::string& host,
21+
const std::string& path) = 0;
22+
virtual void OnSocketUpgrade(const std::string& host,
23+
const std::string& path,
2224
const std::string& accept_key) = 0;
2325
virtual void OnWsFrame(const std::vector<char>& frame) = 0;
2426
virtual ~Delegate() {}

src/inspector_socket_server.cc

+45-30
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,42 @@ namespace inspector {
1616
// depend on inspector_socket_server.h
1717
std::string FormatWsAddress(const std::string& host, int port,
1818
const std::string& target_id,
19-
bool include_protocol) {
19+
bool include_protocol);
20+
namespace {
21+
22+
static const uint8_t PROTOCOL_JSON[] = {
23+
#include "v8_inspector_protocol_json.h" // NOLINT(build/include_order)
24+
};
25+
26+
void Escape(std::string* string) {
27+
for (char& c : *string) {
28+
c = (c == '\"' || c == '\\') ? '_' : c;
29+
}
30+
}
31+
32+
std::string FormatHostPort(const std::string& host, int port) {
2033
// Host is valid (socket was bound) so colon means it's a v6 IP address
2134
bool v6 = host.find(':') != std::string::npos;
2235
std::ostringstream url;
23-
if (include_protocol)
24-
url << "ws://";
2536
if (v6) {
2637
url << '[';
2738
}
2839
url << host;
2940
if (v6) {
3041
url << ']';
3142
}
32-
url << ':' << port << '/' << target_id;
43+
url << ':' << port;
3344
return url.str();
3445
}
3546

36-
namespace {
37-
38-
static const uint8_t PROTOCOL_JSON[] = {
39-
#include "v8_inspector_protocol_json.h" // NOLINT(build/include_order)
40-
};
41-
42-
void Escape(std::string* string) {
43-
for (char& c : *string) {
44-
c = (c == '\"' || c == '\\') ? '_' : c;
45-
}
47+
std::string FormatAddress(const std::string& host,
48+
const std::string& target_id,
49+
bool include_protocol) {
50+
std::ostringstream url;
51+
if (include_protocol)
52+
url << "ws://";
53+
url << host << '/' << target_id;
54+
return url.str();
4655
}
4756

4857
std::string MapToString(const std::map<std::string, std::string>& object) {
@@ -141,6 +150,11 @@ void SendProtocolJson(InspectorSocket* socket) {
141150
}
142151
} // namespace
143152

153+
std::string FormatWsAddress(const std::string& host, int port,
154+
const std::string& target_id,
155+
bool include_protocol) {
156+
return FormatAddress(FormatHostPort(host, port), target_id, include_protocol);
157+
}
144158

145159
class Closer {
146160
public:
@@ -213,8 +227,8 @@ class SocketSession {
213227
~Delegate() {
214228
server_->SessionTerminated(session_id_);
215229
}
216-
void OnHttpGet(const std::string& path) override;
217-
void OnSocketUpgrade(const std::string& path,
230+
void OnHttpGet(const std::string& host, const std::string& path) override;
231+
void OnSocketUpgrade(const std::string& host, const std::string& path,
218232
const std::string& ws_key) override;
219233
void OnWsFrame(const std::vector<char>& data) override;
220234

@@ -320,6 +334,7 @@ void InspectorSocketServer::SessionTerminated(int session_id) {
320334
}
321335

322336
bool InspectorSocketServer::HandleGetRequest(int session_id,
337+
const std::string& host,
323338
const std::string& path) {
324339
SocketSession* session = Session(session_id);
325340
InspectorSocket* socket = session->ws_socket();
@@ -328,25 +343,20 @@ bool InspectorSocketServer::HandleGetRequest(int session_id,
328343
return false;
329344

330345
if (MatchPathSegment(command, "list") || command[0] == '\0') {
331-
SendListResponse(socket, session);
346+
SendListResponse(socket, host, session);
332347
return true;
333348
} else if (MatchPathSegment(command, "protocol")) {
334349
SendProtocolJson(socket);
335350
return true;
336351
} else if (MatchPathSegment(command, "version")) {
337352
SendVersionResponse(socket);
338353
return true;
339-
} else if (const char* target_id = MatchPathSegment(command, "activate")) {
340-
if (TargetExists(target_id)) {
341-
SendHttpResponse(socket, "Target activated");
342-
return true;
343-
}
344-
return false;
345354
}
346355
return false;
347356
}
348357

349358
void InspectorSocketServer::SendListResponse(InspectorSocket* socket,
359+
const std::string& host,
350360
SocketSession* session) {
351361
std::vector<std::map<std::string, std::string>> response;
352362
for (const std::string& id : delegate_->GetTargetIds()) {
@@ -371,15 +381,18 @@ void InspectorSocketServer::SendListResponse(InspectorSocket* socket,
371381
}
372382
}
373383
if (!connected) {
374-
std::string host = socket->GetHost();
375-
int port = session->server_port();
384+
std::string detected_host = host;
385+
if (detected_host.empty()) {
386+
detected_host = FormatHostPort(socket->GetHost(),
387+
session->server_port());
388+
}
376389
std::ostringstream frontend_url;
377390
frontend_url << "chrome-devtools://devtools/bundled";
378391
frontend_url << "/inspector.html?experiments=true&v8only=true&ws=";
379-
frontend_url << FormatWsAddress(host, port, id, false);
392+
frontend_url << FormatAddress(detected_host, id, false);
380393
target_map["devtoolsFrontendUrl"] += frontend_url.str();
381394
target_map["webSocketDebuggerUrl"] =
382-
FormatWsAddress(host, port, id, true);
395+
FormatAddress(detected_host, id, true);
383396
}
384397
}
385398
SendHttpResponse(socket, MapsToString(response));
@@ -531,12 +544,14 @@ void SocketSession::Send(const std::string& message) {
531544
ws_socket_->Write(message.data(), message.length());
532545
}
533546

534-
void SocketSession::Delegate::OnHttpGet(const std::string& path) {
535-
if (!server_->HandleGetRequest(session_id_, path))
547+
void SocketSession::Delegate::OnHttpGet(const std::string& host,
548+
const std::string& path) {
549+
if (!server_->HandleGetRequest(session_id_, host, path))
536550
Session()->ws_socket()->CancelHandshake();
537551
}
538552

539-
void SocketSession::Delegate::OnSocketUpgrade(const std::string& path,
553+
void SocketSession::Delegate::OnSocketUpgrade(const std::string& host,
554+
const std::string& path,
540555
const std::string& ws_key) {
541556
std::string id = path.empty() ? path : path.substr(1);
542557
server_->SessionStarted(session_id_, id, ws_key);

src/inspector_socket_server.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class InspectorSocketServer {
6767

6868
// Session connection lifecycle
6969
void Accept(int server_port, uv_stream_t* server_socket);
70-
bool HandleGetRequest(int session_id, const std::string& path);
70+
bool HandleGetRequest(int session_id, const std::string& host,
71+
const std::string& path);
7172
void SessionStarted(int session_id, const std::string& target_id,
7273
const std::string& ws_id);
7374
void SessionTerminated(int session_id);
@@ -77,7 +78,8 @@ class InspectorSocketServer {
7778
SocketSession* Session(int session_id);
7879

7980
private:
80-
void SendListResponse(InspectorSocket* socket, SocketSession* session);
81+
void SendListResponse(InspectorSocket* socket, const std::string& host,
82+
SocketSession* session);
8183
bool TargetExists(const std::string& id);
8284

8385
enum class ServerState {kNew, kRunning, kStopping, kStopped};

test/cctest/test_inspector_socket.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,11 @@ class TestInspectorDelegate : public InspectorSocket::Delegate {
112112
delegate = nullptr;
113113
}
114114

115-
void OnHttpGet(const std::string& path) override {
115+
void OnHttpGet(const std::string& host, const std::string& path) override {
116116
process(kInspectorHandshakeHttpGet, path);
117117
}
118118

119-
void OnSocketUpgrade(const std::string& path,
119+
void OnSocketUpgrade(const std::string& host, const std::string& path,
120120
const std::string& ws_key) override {
121121
ws_key_ = ws_key;
122122
process(kInspectorHandshakeUpgraded, path);

test/common/inspector-helper.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,11 @@ class NodeInstance {
365365
}
366366
}
367367

368-
httpGet(host, path) {
368+
httpGet(host, path, hostHeaderValue) {
369369
console.log('[test]', `Testing ${path}`);
370+
const headers = hostHeaderValue ? { 'Host': hostHeaderValue } : null;
370371
return this.portPromise.then((port) => new Promise((resolve, reject) => {
371-
const req = http.get({ host, port, path }, (res) => {
372+
const req = http.get({ host, port, path, headers }, (res) => {
372373
let response = '';
373374
res.setEncoding('utf8');
374375
res
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
const common = require('../common');
4+
5+
common.skipIfInspectorDisabled();
6+
7+
const assert = require('assert');
8+
const { NodeInstance } = require('../common/inspector-helper.js');
9+
10+
common.crashOnUnhandledRejection();
11+
12+
async function test() {
13+
const madeUpHost = '111.111.111.111:11111';
14+
const child = new NodeInstance(undefined, 'var a = 1');
15+
const response = await child.httpGet(null, '/json', madeUpHost);
16+
assert.ok(
17+
response[0].webSocketDebuggerUrl.startsWith(`ws://${madeUpHost}`),
18+
response[0].webSocketDebuggerUrl);
19+
child.kill();
20+
}
21+
22+
test();

test/sequential/test-inspector.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ function checkListResponse(response) {
1111
assert.strictEqual(1, response.length);
1212
assert.ok(response[0].devtoolsFrontendUrl);
1313
assert.ok(
14-
/ws:\/\/127\.0\.0\.1:\d+\/[0-9A-Fa-f]{8}-/
15-
.test(response[0].webSocketDebuggerUrl));
14+
/ws:\/\/localhost:\d+\/[0-9A-Fa-f]{8}-/
15+
.test(response[0].webSocketDebuggerUrl),
16+
response[0].webSocketDebuggerUrl);
1617
}
1718

1819
function checkVersion(response) {

0 commit comments

Comments
 (0)