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: https://github.com/nodejs/node/pull/19664 Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
This commit is contained in:
parent
6de1a12e49
commit
a9a1f12b42
@ -495,12 +495,12 @@ class HttpHandler : public ProtocolHandler {
|
||||
CancelHandshake();
|
||||
return;
|
||||
} else if (!event.upgrade) {
|
||||
delegate()->OnHttpGet(event.path);
|
||||
delegate()->OnHttpGet(event.host, event.path);
|
||||
} else if (event.ws_key.empty()) {
|
||||
CancelHandshake();
|
||||
return;
|
||||
} else {
|
||||
delegate()->OnSocketUpgrade(event.path, event.ws_key);
|
||||
delegate()->OnSocketUpgrade(event.host, event.path, event.ws_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,10 @@ class InspectorSocket {
|
||||
public:
|
||||
class Delegate {
|
||||
public:
|
||||
virtual void OnHttpGet(const std::string& path) = 0;
|
||||
virtual void OnSocketUpgrade(const std::string& path,
|
||||
virtual void OnHttpGet(const std::string& host,
|
||||
const std::string& path) = 0;
|
||||
virtual void OnSocketUpgrade(const std::string& host,
|
||||
const std::string& path,
|
||||
const std::string& accept_key) = 0;
|
||||
virtual void OnWsFrame(const std::vector<char>& frame) = 0;
|
||||
virtual ~Delegate() {}
|
||||
|
@ -16,23 +16,7 @@ namespace inspector {
|
||||
// depend on inspector_socket_server.h
|
||||
std::string FormatWsAddress(const std::string& host, int port,
|
||||
const std::string& target_id,
|
||||
bool include_protocol) {
|
||||
// Host is valid (socket was bound) so colon means it's a v6 IP address
|
||||
bool v6 = host.find(':') != std::string::npos;
|
||||
std::ostringstream url;
|
||||
if (include_protocol)
|
||||
url << "ws://";
|
||||
if (v6) {
|
||||
url << '[';
|
||||
}
|
||||
url << host;
|
||||
if (v6) {
|
||||
url << ']';
|
||||
}
|
||||
url << ':' << port << '/' << target_id;
|
||||
return url.str();
|
||||
}
|
||||
|
||||
bool include_protocol);
|
||||
namespace {
|
||||
|
||||
static const uint8_t PROTOCOL_JSON[] = {
|
||||
@ -45,6 +29,31 @@ void Escape(std::string* string) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string FormatHostPort(const std::string& host, int port) {
|
||||
// Host is valid (socket was bound) so colon means it's a v6 IP address
|
||||
bool v6 = host.find(':') != std::string::npos;
|
||||
std::ostringstream url;
|
||||
if (v6) {
|
||||
url << '[';
|
||||
}
|
||||
url << host;
|
||||
if (v6) {
|
||||
url << ']';
|
||||
}
|
||||
url << ':' << port;
|
||||
return url.str();
|
||||
}
|
||||
|
||||
std::string FormatAddress(const std::string& host,
|
||||
const std::string& target_id,
|
||||
bool include_protocol) {
|
||||
std::ostringstream url;
|
||||
if (include_protocol)
|
||||
url << "ws://";
|
||||
url << host << '/' << target_id;
|
||||
return url.str();
|
||||
}
|
||||
|
||||
std::string MapToString(const std::map<std::string, std::string>& object) {
|
||||
bool first = true;
|
||||
std::ostringstream json;
|
||||
@ -141,6 +150,11 @@ void SendProtocolJson(InspectorSocket* socket) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string FormatWsAddress(const std::string& host, int port,
|
||||
const std::string& target_id,
|
||||
bool include_protocol) {
|
||||
return FormatAddress(FormatHostPort(host, port), target_id, include_protocol);
|
||||
}
|
||||
|
||||
class Closer {
|
||||
public:
|
||||
@ -213,8 +227,8 @@ class SocketSession {
|
||||
~Delegate() {
|
||||
server_->SessionTerminated(session_id_);
|
||||
}
|
||||
void OnHttpGet(const std::string& path) override;
|
||||
void OnSocketUpgrade(const std::string& path,
|
||||
void OnHttpGet(const std::string& host, const std::string& path) override;
|
||||
void OnSocketUpgrade(const std::string& host, const std::string& path,
|
||||
const std::string& ws_key) override;
|
||||
void OnWsFrame(const std::vector<char>& data) override;
|
||||
|
||||
@ -320,6 +334,7 @@ void InspectorSocketServer::SessionTerminated(int session_id) {
|
||||
}
|
||||
|
||||
bool InspectorSocketServer::HandleGetRequest(int session_id,
|
||||
const std::string& host,
|
||||
const std::string& path) {
|
||||
SocketSession* session = Session(session_id);
|
||||
InspectorSocket* socket = session->ws_socket();
|
||||
@ -328,7 +343,7 @@ bool InspectorSocketServer::HandleGetRequest(int session_id,
|
||||
return false;
|
||||
|
||||
if (MatchPathSegment(command, "list") || command[0] == '\0') {
|
||||
SendListResponse(socket, session);
|
||||
SendListResponse(socket, host, session);
|
||||
return true;
|
||||
} else if (MatchPathSegment(command, "protocol")) {
|
||||
SendProtocolJson(socket);
|
||||
@ -336,17 +351,12 @@ bool InspectorSocketServer::HandleGetRequest(int session_id,
|
||||
} else if (MatchPathSegment(command, "version")) {
|
||||
SendVersionResponse(socket);
|
||||
return true;
|
||||
} else if (const char* target_id = MatchPathSegment(command, "activate")) {
|
||||
if (TargetExists(target_id)) {
|
||||
SendHttpResponse(socket, "Target activated");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void InspectorSocketServer::SendListResponse(InspectorSocket* socket,
|
||||
const std::string& host,
|
||||
SocketSession* session) {
|
||||
std::vector<std::map<std::string, std::string>> response;
|
||||
for (const std::string& id : delegate_->GetTargetIds()) {
|
||||
@ -371,15 +381,18 @@ void InspectorSocketServer::SendListResponse(InspectorSocket* socket,
|
||||
}
|
||||
}
|
||||
if (!connected) {
|
||||
std::string host = socket->GetHost();
|
||||
int port = session->server_port();
|
||||
std::string detected_host = host;
|
||||
if (detected_host.empty()) {
|
||||
detected_host = FormatHostPort(socket->GetHost(),
|
||||
session->server_port());
|
||||
}
|
||||
std::ostringstream frontend_url;
|
||||
frontend_url << "chrome-devtools://devtools/bundled";
|
||||
frontend_url << "/inspector.html?experiments=true&v8only=true&ws=";
|
||||
frontend_url << FormatWsAddress(host, port, id, false);
|
||||
frontend_url << FormatAddress(detected_host, id, false);
|
||||
target_map["devtoolsFrontendUrl"] += frontend_url.str();
|
||||
target_map["webSocketDebuggerUrl"] =
|
||||
FormatWsAddress(host, port, id, true);
|
||||
FormatAddress(detected_host, id, true);
|
||||
}
|
||||
}
|
||||
SendHttpResponse(socket, MapsToString(response));
|
||||
@ -531,12 +544,14 @@ void SocketSession::Send(const std::string& message) {
|
||||
ws_socket_->Write(message.data(), message.length());
|
||||
}
|
||||
|
||||
void SocketSession::Delegate::OnHttpGet(const std::string& path) {
|
||||
if (!server_->HandleGetRequest(session_id_, path))
|
||||
void SocketSession::Delegate::OnHttpGet(const std::string& host,
|
||||
const std::string& path) {
|
||||
if (!server_->HandleGetRequest(session_id_, host, path))
|
||||
Session()->ws_socket()->CancelHandshake();
|
||||
}
|
||||
|
||||
void SocketSession::Delegate::OnSocketUpgrade(const std::string& path,
|
||||
void SocketSession::Delegate::OnSocketUpgrade(const std::string& host,
|
||||
const std::string& path,
|
||||
const std::string& ws_key) {
|
||||
std::string id = path.empty() ? path : path.substr(1);
|
||||
server_->SessionStarted(session_id_, id, ws_key);
|
||||
|
@ -67,7 +67,8 @@ class InspectorSocketServer {
|
||||
|
||||
// Session connection lifecycle
|
||||
void Accept(int server_port, uv_stream_t* server_socket);
|
||||
bool HandleGetRequest(int session_id, const std::string& path);
|
||||
bool HandleGetRequest(int session_id, const std::string& host,
|
||||
const std::string& path);
|
||||
void SessionStarted(int session_id, const std::string& target_id,
|
||||
const std::string& ws_id);
|
||||
void SessionTerminated(int session_id);
|
||||
@ -77,7 +78,8 @@ class InspectorSocketServer {
|
||||
SocketSession* Session(int session_id);
|
||||
|
||||
private:
|
||||
void SendListResponse(InspectorSocket* socket, SocketSession* session);
|
||||
void SendListResponse(InspectorSocket* socket, const std::string& host,
|
||||
SocketSession* session);
|
||||
bool TargetExists(const std::string& id);
|
||||
|
||||
enum class ServerState {kNew, kRunning, kStopping, kStopped};
|
||||
|
@ -112,11 +112,11 @@ class TestInspectorDelegate : public InspectorSocket::Delegate {
|
||||
delegate = nullptr;
|
||||
}
|
||||
|
||||
void OnHttpGet(const std::string& path) override {
|
||||
void OnHttpGet(const std::string& host, const std::string& path) override {
|
||||
process(kInspectorHandshakeHttpGet, path);
|
||||
}
|
||||
|
||||
void OnSocketUpgrade(const std::string& path,
|
||||
void OnSocketUpgrade(const std::string& host, const std::string& path,
|
||||
const std::string& ws_key) override {
|
||||
ws_key_ = ws_key;
|
||||
process(kInspectorHandshakeUpgraded, path);
|
||||
|
@ -365,10 +365,11 @@ class NodeInstance {
|
||||
}
|
||||
}
|
||||
|
||||
httpGet(host, path) {
|
||||
httpGet(host, path, hostHeaderValue) {
|
||||
console.log('[test]', `Testing ${path}`);
|
||||
const headers = hostHeaderValue ? { 'Host': hostHeaderValue } : null;
|
||||
return this.portPromise.then((port) => new Promise((resolve, reject) => {
|
||||
const req = http.get({ host, port, path }, (res) => {
|
||||
const req = http.get({ host, port, path, headers }, (res) => {
|
||||
let response = '';
|
||||
res.setEncoding('utf8');
|
||||
res
|
||||
|
22
test/parallel/test-inspector-reported-host.js
Normal file
22
test/parallel/test-inspector-reported-host.js
Normal file
@ -0,0 +1,22 @@
|
||||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
|
||||
common.skipIfInspectorDisabled();
|
||||
|
||||
const assert = require('assert');
|
||||
const { NodeInstance } = require('../common/inspector-helper.js');
|
||||
|
||||
common.crashOnUnhandledRejection();
|
||||
|
||||
async function test() {
|
||||
const madeUpHost = '111.111.111.111:11111';
|
||||
const child = new NodeInstance(undefined, 'var a = 1');
|
||||
const response = await child.httpGet(null, '/json', madeUpHost);
|
||||
assert.ok(
|
||||
response[0].webSocketDebuggerUrl.startsWith(`ws://${madeUpHost}`),
|
||||
response[0].webSocketDebuggerUrl);
|
||||
child.kill();
|
||||
}
|
||||
|
||||
test();
|
@ -11,8 +11,9 @@ function checkListResponse(response) {
|
||||
assert.strictEqual(1, response.length);
|
||||
assert.ok(response[0].devtoolsFrontendUrl);
|
||||
assert.ok(
|
||||
/ws:\/\/127\.0\.0\.1:\d+\/[0-9A-Fa-f]{8}-/
|
||||
.test(response[0].webSocketDebuggerUrl));
|
||||
/ws:\/\/localhost:\d+\/[0-9A-Fa-f]{8}-/
|
||||
.test(response[0].webSocketDebuggerUrl),
|
||||
response[0].webSocketDebuggerUrl);
|
||||
}
|
||||
|
||||
function checkVersion(response) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user