@@ -51,7 +51,14 @@ void PrintDebuggerReadyMessage(int port) {
51
51
}
52
52
53
53
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
+ }
55
62
}
56
63
57
64
void DisposeInspector (inspector_socket_t * socket, int status) {
@@ -98,7 +105,21 @@ void SendVersionResponse(inspector_socket_t* socket) {
98
105
SendHttpResponse (socket, buffer, len);
99
106
}
100
107
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) {
102
123
const char LIST_RESPONSE_TEMPLATE[] =
103
124
" [ {"
104
125
" \" description\" : \" node.js instance\" ,"
@@ -110,45 +131,60 @@ void SendTargentsListResponse(inspector_socket_t* socket, int port) {
110
131
" \" id\" : \" %d\" ,"
111
132
" \" title\" : \" %s\" ,"
112
133
" \" type\" : \" node\" ,"
134
+ " \" url\" : \" %s\" ,"
113
135
" \" webSocketDebuggerUrl\" : \" ws://localhost:%d%s\" "
114
136
" } ]" ;
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;
127
167
}
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 ;
133
169
}
134
170
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,
136
173
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" )) {
142
181
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 ;
148
186
const char TARGET_ACTIVATED[] = " Target activated" ;
149
187
SendHttpResponse (socket, TARGET_ACTIVATED, sizeof (TARGET_ACTIVATED) - 1 );
150
- } else {
151
- return false ;
152
188
}
153
189
return true ;
154
190
}
@@ -166,7 +202,7 @@ class AgentImpl {
166
202
~AgentImpl ();
167
203
168
204
// 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);
170
206
// Stop the inspector agent
171
207
void Stop ();
172
208
@@ -227,6 +263,9 @@ class AgentImpl {
227
263
int frontend_session_id_;
228
264
int backend_session_id_;
229
265
266
+ std::string script_name_;
267
+ std::string script_path_;
268
+
230
269
friend class ChannelImpl ;
231
270
friend class DispatchOnInspectorBackendTask ;
232
271
friend class SetConnectedTask ;
@@ -442,10 +481,13 @@ void InspectorWrapConsoleCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
442
481
array).ToLocalChecked ());
443
482
}
444
483
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) {
446
486
auto env = parent_env_;
447
487
inspector_ = new V8NodeInspector (this , env, platform);
448
488
platform_ = platform;
489
+ if (path != nullptr )
490
+ script_name_ = path;
449
491
450
492
InstallInspectorOnProcess ();
451
493
@@ -566,7 +608,8 @@ bool AgentImpl::OnInspectorHandshakeIO(inspector_socket_t* socket,
566
608
AgentImpl* agent = static_cast <AgentImpl*>(socket->data );
567
609
switch (state) {
568
610
case kInspectorHandshakeHttpGet :
569
- return RespondToGet (socket, path, agent->port_ );
611
+ return RespondToGet (socket, agent->script_name_ , agent->script_path_ , path,
612
+ agent->port_ );
570
613
case kInspectorHandshakeUpgrading :
571
614
return AcceptsConnection (socket, path);
572
615
case kInspectorHandshakeUpgraded :
@@ -635,6 +678,12 @@ void AgentImpl::WorkerRunIO() {
635
678
err = uv_async_init (&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO);
636
679
CHECK_EQ (err, 0 );
637
680
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
+ }
638
687
uv_tcp_init (&child_loop_, &server);
639
688
uv_ip4_addr (" 0.0.0.0" , port_, &addr);
640
689
server.data = this ;
@@ -752,8 +801,9 @@ Agent::~Agent() {
752
801
delete impl;
753
802
}
754
803
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 );
757
807
}
758
808
759
809
void Agent::Stop () {
0 commit comments