Skip to content

Commit 609a265

Browse files
Eugene Ostroukhovofrobots
Eugene Ostroukhov
authored andcommitted
inspector: use script name for target title
Changes inspector integration to use Node.js script file name as target title (reported in JSON and shown in developer tools UIs). It will also report file:// URL for the script as some tools seem to use that field to open the script in the editor. PR-URL: #8243 Reviewed-By: bnoordhuis - Ben Noordhuis <[email protected]>
1 parent 9826a79 commit 609a265

File tree

3 files changed

+101
-45
lines changed

3 files changed

+101
-45
lines changed

src/inspector_agent.cc

+87-37
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,14 @@ void PrintDebuggerReadyMessage(int port) {
5151
}
5252

5353
bool AcceptsConnection(inspector_socket_t* socket, const std::string& path) {
54-
return 0 == path.compare(0, sizeof(DEVTOOLS_PATH) - 1, DEVTOOLS_PATH);
54+
return StringEqualNoCaseN(path.c_str(), DEVTOOLS_PATH,
55+
sizeof(DEVTOOLS_PATH) - 1);
56+
}
57+
58+
void Escape(std::string* string) {
59+
for (char& c : *string) {
60+
c = (c == '\"' || c == '\\') ? '_' : c;
61+
}
5562
}
5663

5764
void DisposeInspector(inspector_socket_t* socket, int status) {
@@ -98,7 +105,21 @@ void SendVersionResponse(inspector_socket_t* socket) {
98105
SendHttpResponse(socket, buffer, len);
99106
}
100107

101-
void SendTargentsListResponse(inspector_socket_t* socket, int port) {
108+
std::string GetProcessTitle() {
109+
// uv_get_process_title will trim the title if it is too long.
110+
char title[2048];
111+
int err = uv_get_process_title(title, sizeof(title));
112+
if (err == 0) {
113+
return title;
114+
} else {
115+
return "Node.js";
116+
}
117+
}
118+
119+
void SendTargentsListResponse(inspector_socket_t* socket,
120+
const std::string& script_name_,
121+
const std::string& script_path_,
122+
int port) {
102123
const char LIST_RESPONSE_TEMPLATE[] =
103124
"[ {"
104125
" \"description\": \"node.js instance\","
@@ -110,45 +131,60 @@ void SendTargentsListResponse(inspector_socket_t* socket, int port) {
110131
" \"id\": \"%d\","
111132
" \"title\": \"%s\","
112133
" \"type\": \"node\","
134+
" \"url\": \"%s\","
113135
" \"webSocketDebuggerUrl\": \"ws://localhost:%d%s\""
114136
"} ]";
115-
char buffer[sizeof(LIST_RESPONSE_TEMPLATE) + 4096];
116-
char title[2048]; // uv_get_process_title trims the title if too long
117-
int err = uv_get_process_title(title, sizeof(title));
118-
if (err != 0) {
119-
snprintf(title, sizeof(title), "Node.js");
120-
}
121-
char* c = title;
122-
while (*c != '\0') {
123-
if (*c < ' ' || *c == '\"') {
124-
*c = '_';
125-
}
126-
c++;
137+
std::string title = script_name_.empty() ? GetProcessTitle() : script_name_;
138+
139+
// This attribute value is a "best effort" URL that is passed as a JSON
140+
// string. It is not guaranteed to resolve to a valid resource.
141+
std::string url = "file://" + script_path_;
142+
143+
Escape(&title);
144+
Escape(&url);
145+
146+
const int NUMERIC_FIELDS_LENGTH = 5 * 2 + 20; // 2 x port + 1 x pid (64 bit)
147+
148+
int buf_len = sizeof(LIST_RESPONSE_TEMPLATE) + sizeof(DEVTOOLS_HASH) +
149+
sizeof(DEVTOOLS_PATH) * 2 + title.length() +
150+
url.length() + NUMERIC_FIELDS_LENGTH;
151+
std::string buffer(buf_len, '\0');
152+
153+
int len = snprintf(&buffer[0], buf_len, LIST_RESPONSE_TEMPLATE,
154+
DEVTOOLS_HASH, port, DEVTOOLS_PATH, getpid(),
155+
title.c_str(), url.c_str(),
156+
port, DEVTOOLS_PATH);
157+
buffer.resize(len);
158+
ASSERT_LT(len, buf_len); // Buffer should be big enough!
159+
SendHttpResponse(socket, buffer.data(), len);
160+
}
161+
162+
const char* match_path_segment(const char* path, const char* expected) {
163+
size_t len = strlen(expected);
164+
if (StringEqualNoCaseN(path, expected, len)) {
165+
if (path[len] == '/') return path + len + 1;
166+
if (path[len] == '\0') return path + len;
127167
}
128-
size_t len = snprintf(buffer, sizeof(buffer), LIST_RESPONSE_TEMPLATE,
129-
DEVTOOLS_HASH, port, DEVTOOLS_PATH, getpid(),
130-
title, port, DEVTOOLS_PATH);
131-
ASSERT_LT(len, sizeof(buffer));
132-
SendHttpResponse(socket, buffer, len);
168+
return nullptr;
133169
}
134170

135-
bool RespondToGet(inspector_socket_t* socket, const std::string& path,
171+
bool RespondToGet(inspector_socket_t* socket, const std::string& script_name_,
172+
const std::string& script_path_, const std::string& path,
136173
int port) {
137-
const char PATH[] = "/json";
138-
const char PATH_LIST[] = "/json/list";
139-
const char PATH_VERSION[] = "/json/version";
140-
const char PATH_ACTIVATE[] = "/json/activate/";
141-
if (0 == path.compare(0, sizeof(PATH_VERSION) - 1, PATH_VERSION)) {
174+
const char* command = match_path_segment(path.c_str(), "/json");
175+
if (command == nullptr)
176+
return false;
177+
178+
if (match_path_segment(command, "list") || command[0] == '\0') {
179+
SendTargentsListResponse(socket, script_name_, script_path_, port);
180+
} else if (match_path_segment(command, "version")) {
142181
SendVersionResponse(socket);
143-
} else if (0 == path.compare(0, sizeof(PATH_LIST) - 1, PATH_LIST) ||
144-
0 == path.compare(0, sizeof(PATH) - 1, PATH)) {
145-
SendTargentsListResponse(socket, port);
146-
} else if (0 == path.compare(0, sizeof(PATH_ACTIVATE) - 1, PATH_ACTIVATE) &&
147-
atoi(path.substr(sizeof(PATH_ACTIVATE) - 1).c_str()) == getpid()) {
182+
} else {
183+
const char* pid = match_path_segment(command, "activate");
184+
if (pid == nullptr || atoi(pid) != getpid())
185+
return false;
148186
const char TARGET_ACTIVATED[] = "Target activated";
149187
SendHttpResponse(socket, TARGET_ACTIVATED, sizeof(TARGET_ACTIVATED) - 1);
150-
} else {
151-
return false;
152188
}
153189
return true;
154190
}
@@ -166,7 +202,7 @@ class AgentImpl {
166202
~AgentImpl();
167203

168204
// Start the inspector agent thread
169-
bool Start(v8::Platform* platform, int port, bool wait);
205+
bool Start(v8::Platform* platform, const char* path, int port, bool wait);
170206
// Stop the inspector agent
171207
void Stop();
172208

@@ -227,6 +263,9 @@ class AgentImpl {
227263
int frontend_session_id_;
228264
int backend_session_id_;
229265

266+
std::string script_name_;
267+
std::string script_path_;
268+
230269
friend class ChannelImpl;
231270
friend class DispatchOnInspectorBackendTask;
232271
friend class SetConnectedTask;
@@ -442,10 +481,13 @@ void InspectorWrapConsoleCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
442481
array).ToLocalChecked());
443482
}
444483

445-
bool AgentImpl::Start(v8::Platform* platform, int port, bool wait) {
484+
bool AgentImpl::Start(v8::Platform* platform, const char* path,
485+
int port, bool wait) {
446486
auto env = parent_env_;
447487
inspector_ = new V8NodeInspector(this, env, platform);
448488
platform_ = platform;
489+
if (path != nullptr)
490+
script_name_ = path;
449491

450492
InstallInspectorOnProcess();
451493

@@ -566,7 +608,8 @@ bool AgentImpl::OnInspectorHandshakeIO(inspector_socket_t* socket,
566608
AgentImpl* agent = static_cast<AgentImpl*>(socket->data);
567609
switch (state) {
568610
case kInspectorHandshakeHttpGet:
569-
return RespondToGet(socket, path, agent->port_);
611+
return RespondToGet(socket, agent->script_name_, agent->script_path_, path,
612+
agent->port_);
570613
case kInspectorHandshakeUpgrading:
571614
return AcceptsConnection(socket, path);
572615
case kInspectorHandshakeUpgraded:
@@ -635,6 +678,12 @@ void AgentImpl::WorkerRunIO() {
635678
err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO);
636679
CHECK_EQ(err, 0);
637680
io_thread_req_.data = this;
681+
if (!script_name_.empty()) {
682+
uv_fs_t req;
683+
if (0 == uv_fs_realpath(&child_loop_, &req, script_name_.c_str(), nullptr))
684+
script_path_ = std::string(reinterpret_cast<char*>(req.ptr));
685+
uv_fs_req_cleanup(&req);
686+
}
638687
uv_tcp_init(&child_loop_, &server);
639688
uv_ip4_addr("0.0.0.0", port_, &addr);
640689
server.data = this;
@@ -752,8 +801,9 @@ Agent::~Agent() {
752801
delete impl;
753802
}
754803

755-
bool Agent::Start(v8::Platform* platform, int port, bool wait) {
756-
return impl->Start(platform, port, wait);
804+
bool Agent::Start(v8::Platform* platform, const char* path,
805+
int port, bool wait) {
806+
return impl->Start(platform, path, port, wait);
757807
}
758808

759809
void Agent::Stop() {

src/inspector_agent.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Agent {
2929
~Agent();
3030

3131
// Start the inspector agent thread
32-
bool Start(v8::Platform* platform, int port, bool wait);
32+
bool Start(v8::Platform* platform, const char* path, int port, bool wait);
3333
// Stop the inspector agent
3434
void Stop();
3535

src/node.cc

+13-7
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,10 @@ static struct {
207207
platform_ = nullptr;
208208
}
209209

210-
bool StartInspector(Environment *env, int port, bool wait) {
210+
bool StartInspector(Environment *env, const char* script_path,
211+
int port, bool wait) {
211212
#if HAVE_INSPECTOR
212-
return env->inspector_agent()->Start(platform_, port, wait);
213+
return env->inspector_agent()->Start(platform_, script_path, port, wait);
213214
#else
214215
return true;
215216
#endif // HAVE_INSPECTOR
@@ -220,7 +221,8 @@ static struct {
220221
void Initialize(int thread_pool_size) {}
221222
void PumpMessageLoop(Isolate* isolate) {}
222223
void Dispose() {}
223-
bool StartInspector(Environment *env, int port, bool wait) {
224+
bool StartInspector(Environment *env, const char* script_path,
225+
int port, bool wait) {
224226
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
225227
return false; // make compiler happy
226228
}
@@ -3766,10 +3768,11 @@ static void DispatchMessagesDebugAgentCallback(Environment* env) {
37663768
}
37673769

37683770

3769-
static void StartDebug(Environment* env, bool wait) {
3771+
static void StartDebug(Environment* env, const char* path, bool wait) {
37703772
CHECK(!debugger_running);
37713773
if (use_inspector) {
3772-
debugger_running = v8_platform.StartInspector(env, inspector_port, wait);
3774+
debugger_running = v8_platform.StartInspector(env, path, inspector_port,
3775+
wait);
37733776
} else {
37743777
env->debugger_agent()->set_dispatch_handler(
37753778
DispatchMessagesDebugAgentCallback);
@@ -3831,7 +3834,7 @@ static void DispatchDebugMessagesAsyncCallback(uv_async_t* handle) {
38313834
Environment* env = Environment::GetCurrent(isolate);
38323835
Context::Scope context_scope(env->context());
38333836

3834-
StartDebug(env, false);
3837+
StartDebug(env, nullptr, false);
38353838
EnableDebug(env);
38363839
}
38373840

@@ -4396,7 +4399,10 @@ static void StartNodeInstance(void* arg) {
43964399

43974400
// Start debug agent when argv has --debug
43984401
if (instance_data->use_debug_agent()) {
4399-
StartDebug(&env, debug_wait_connect);
4402+
const char* path = instance_data->argc() > 1
4403+
? instance_data->argv()[1]
4404+
: nullptr;
4405+
StartDebug(&env, path, debug_wait_connect);
44004406
if (use_inspector && !debugger_running) {
44014407
exit(12);
44024408
}

0 commit comments

Comments
 (0)