Skip to content

Commit b3f8f89

Browse files
Eugene OstroukhovMylesBorins
Eugene Ostroukhov
authored andcommitted
inspector: no URLs when the debugger is connected
By convention, inspector protocol targets do not advertise connection URLs when the frontend is already connected as multiple inspector protocol connections are not supported. PR-URL: #8919 Reviewed-By: Aleksey Kozyatinskiy <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 7fbfb73 commit b3f8f89

File tree

3 files changed

+82
-65
lines changed

3 files changed

+82
-65
lines changed

src/inspector_agent.cc

+64-65
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#include "libplatform/libplatform.h"
2222

23+
#include <map>
24+
#include <sstream>
2325
#include <string.h>
2426
#include <utility>
2527
#include <vector>
@@ -53,6 +55,21 @@ void PrintDebuggerReadyMessage(int port, const std::string& id) {
5355
fflush(stderr);
5456
}
5557

58+
std::string MapToString(const std::map<std::string, std::string> object) {
59+
std::ostringstream json;
60+
json << "[ {\n";
61+
bool first = true;
62+
for (const auto& name_value : object) {
63+
if (!first)
64+
json << ",\n";
65+
json << " \"" << name_value.first << "\": \"";
66+
json << name_value.second << "\"";
67+
first = false;
68+
}
69+
json << "\n} ]";
70+
return json.str();
71+
}
72+
5673
void Escape(std::string* string) {
5774
for (char& c : *string) {
5875
c = (c == '\"' || c == '\\') ? '_' : c;
@@ -74,33 +91,23 @@ void OnBufferAlloc(uv_handle_t* handle, size_t len, uv_buf_t* buf) {
7491
buf->len = len;
7592
}
7693

77-
void SendHttpResponse(InspectorSocket* socket, const char* response,
78-
size_t len) {
94+
void SendHttpResponse(InspectorSocket* socket, const std::string& response) {
7995
const char HEADERS[] = "HTTP/1.0 200 OK\r\n"
8096
"Content-Type: application/json; charset=UTF-8\r\n"
8197
"Cache-Control: no-cache\r\n"
8298
"Content-Length: %zu\r\n"
8399
"\r\n";
84100
char header[sizeof(HEADERS) + 20];
85-
int header_len = snprintf(header, sizeof(header), HEADERS, len);
101+
int header_len = snprintf(header, sizeof(header), HEADERS, response.size());
86102
inspector_write(socket, header, header_len);
87-
inspector_write(socket, response, len);
103+
inspector_write(socket, response.data(), response.size());
88104
}
89105

90106
void SendVersionResponse(InspectorSocket* socket) {
91-
const char VERSION_RESPONSE_TEMPLATE[] =
92-
"[ {"
93-
" \"Browser\": \"node.js/%s\","
94-
" \"Protocol-Version\": \"1.1\","
95-
" \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
96-
"(KHTML, like Gecko) Chrome/45.0.2446.0 Safari/537.36\","
97-
" \"WebKit-Version\": \"537.36 (@198122)\""
98-
"} ]";
99-
char buffer[sizeof(VERSION_RESPONSE_TEMPLATE) + 128];
100-
size_t len = snprintf(buffer, sizeof(buffer), VERSION_RESPONSE_TEMPLATE,
101-
NODE_VERSION);
102-
ASSERT_LT(len, sizeof(buffer));
103-
SendHttpResponse(socket, buffer, len);
107+
std::map<std::string, std::string> response;
108+
response["Browser"] = "node.js/" NODE_VERSION;
109+
response["Protocol-Version"] = "1.1";
110+
SendHttpResponse(socket, MapToString(response));
104111
}
105112

106113
std::string GetProcessTitle() {
@@ -114,47 +121,6 @@ std::string GetProcessTitle() {
114121
}
115122
}
116123

117-
void SendTargentsListResponse(InspectorSocket* socket,
118-
const std::string& script_name_,
119-
const std::string& script_path_,
120-
const std::string& id,
121-
const std::string& ws_url) {
122-
const char LIST_RESPONSE_TEMPLATE[] =
123-
"[ {"
124-
" \"description\": \"node.js instance\","
125-
" \"devtoolsFrontendUrl\": "
126-
"\"https://chrome-devtools-frontend.appspot.com/serve_file/"
127-
"@" V8_INSPECTOR_REVISION
128-
"/inspector.html?experiments=true&v8only=true"
129-
"&ws=%s\","
130-
" \"faviconUrl\": \"https://nodejs.org/static/favicon.ico\","
131-
" \"id\": \"%s\","
132-
" \"title\": \"%s\","
133-
" \"type\": \"node\","
134-
" \"url\": \"%s\","
135-
" \"webSocketDebuggerUrl\": \"ws://%s\""
136-
"} ]";
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-
int buf_len = sizeof(LIST_RESPONSE_TEMPLATE) + ws_url.length() * 2 +
147-
id.length() + title.length() + url.length();
148-
std::string buffer(buf_len, '\0');
149-
150-
int len = snprintf(&buffer[0], buf_len, LIST_RESPONSE_TEMPLATE,
151-
ws_url.c_str(), id.c_str(), title.c_str(), url.c_str(),
152-
ws_url.c_str());
153-
buffer.resize(len);
154-
ASSERT_LT(len, buf_len); // Buffer should be big enough!
155-
SendHttpResponse(socket, buffer.data(), len);
156-
}
157-
158124
void SendProtocolJson(InspectorSocket* socket) {
159125
z_stream strm;
160126
strm.zalloc = Z_NULL;
@@ -167,13 +133,13 @@ void SendProtocolJson(InspectorSocket* socket) {
167133
PROTOCOL_JSON[2];
168134
strm.next_in = const_cast<uint8_t*>(PROTOCOL_JSON + 3);
169135
strm.avail_in = sizeof(PROTOCOL_JSON) - 3;
170-
std::vector<char> data(kDecompressedSize);
136+
std::string data(kDecompressedSize, '\0');
171137
strm.next_out = reinterpret_cast<Byte*>(&data[0]);
172138
strm.avail_out = data.size();
173139
CHECK_EQ(Z_STREAM_END, inflate(&strm, Z_FINISH));
174140
CHECK_EQ(0, strm.avail_out);
175141
CHECK_EQ(Z_OK, inflateEnd(&strm));
176-
SendHttpResponse(socket, &data[0], data.size());
142+
SendHttpResponse(socket, data);
177143
}
178144

179145
const char* match_path_segment(const char* path, const char* expected) {
@@ -205,6 +171,12 @@ std::string GenerateID() {
205171
return uuid;
206172
}
207173

174+
// std::to_string is not available on Smart OS and ARM flavours
175+
const std::string to_string(uint64_t number) {
176+
std::ostringstream result;
177+
result << number;
178+
return result.str();
179+
}
208180
} // namespace
209181

210182

@@ -253,8 +225,9 @@ class AgentImpl {
253225
void PostIncomingMessage(const String16& message);
254226
void WaitForFrontendMessage();
255227
void NotifyMessageReceived();
256-
bool RespondToGet(InspectorSocket* socket, const std::string& path);
257228
State ToState(State state);
229+
void SendTargentsListResponse(InspectorSocket* socket);
230+
bool RespondToGet(InspectorSocket* socket, const std::string& path);
258231

259232
uv_sem_t start_sem_;
260233
ConditionVariable incoming_message_cond_;
@@ -673,14 +646,41 @@ void AgentImpl::OnRemoteDataIO(InspectorSocket* socket,
673646
}
674647
}
675648

649+
void AgentImpl::SendTargentsListResponse(InspectorSocket* socket) {
650+
std::map<std::string, std::string> response;
651+
response["description"] = "node.js instance";
652+
response["faviconUrl"] = "https://nodejs.org/static/favicon.ico";
653+
response["id"] = id_;
654+
response["title"] = script_name_.empty() ? GetProcessTitle() : script_name_;
655+
Escape(&response["title"]);
656+
response["type"] = "node";
657+
// This attribute value is a "best effort" URL that is passed as a JSON
658+
// string. It is not guaranteed to resolve to a valid resource.
659+
response["url"] = "file://" + script_path_;
660+
Escape(&response["url"]);
661+
662+
if (!client_socket_) {
663+
std::string address = GetWsUrl(port_, id_);
664+
665+
std::ostringstream frontend_url;
666+
frontend_url << "https://chrome-devtools-frontend.appspot.com/serve_file/@";
667+
frontend_url << V8_INSPECTOR_REVISION;
668+
frontend_url << "/inspector.html?experiments=true&v8only=true&ws=";
669+
frontend_url << address;
670+
671+
response["devtoolsFrontendUrl"] += frontend_url.str();
672+
response["webSocketDebuggerUrl"] = "ws://" + address;
673+
}
674+
SendHttpResponse(socket, MapToString(response));
675+
}
676+
676677
bool AgentImpl::RespondToGet(InspectorSocket* socket, const std::string& path) {
677678
const char* command = match_path_segment(path.c_str(), "/json");
678679
if (command == nullptr)
679680
return false;
680681

681682
if (match_path_segment(command, "list") || command[0] == '\0') {
682-
SendTargentsListResponse(socket, script_name_, script_path_, id_,
683-
GetWsUrl(port_, id_));
683+
SendTargentsListResponse(socket);
684684
} else if (match_path_segment(command, "protocol")) {
685685
SendProtocolJson(socket);
686686
} else if (match_path_segment(command, "version")) {
@@ -689,8 +689,7 @@ bool AgentImpl::RespondToGet(InspectorSocket* socket, const std::string& path) {
689689
const char* pid = match_path_segment(command, "activate");
690690
if (pid != id_)
691691
return false;
692-
const char TARGET_ACTIVATED[] = "Target activated";
693-
SendHttpResponse(socket, TARGET_ACTIVATED, sizeof(TARGET_ACTIVATED) - 1);
692+
SendHttpResponse(socket, "Target activated");
694693
}
695694
return true;
696695
}

test/inspector/inspector-helper.js

+9
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,15 @@ TestSession.prototype.disconnect = function(childDone) {
282282
});
283283
};
284284

285+
TestSession.prototype.testHttpResponse = function(path, check) {
286+
return this.enqueue((callback) =>
287+
checkHttpResponse(this.harness_.port, path, (response) => {
288+
check.call(this, response);
289+
callback();
290+
}));
291+
};
292+
293+
285294
const Harness = function(port, childProcess) {
286295
this.port = port;
287296
this.mainScriptPath = mainScript;

test/inspector/test-inspector.js

+9
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ function testInspectScope(session) {
152152
]);
153153
}
154154

155+
function testNoUrlsWhenConnected(session) {
156+
session.testHttpResponse('/json/list', (response) => {
157+
assert.strictEqual(1, response.length);
158+
assert.ok(!response[0].hasOwnProperty('devtoolsFrontendUrl'));
159+
assert.ok(!response[0].hasOwnProperty('webSocketDebuggerUrl'));
160+
});
161+
}
162+
155163
function testWaitsForFrontendDisconnect(session, harness) {
156164
console.log('[test]', 'Verify node waits for the frontend to disconnect');
157165
session.sendInspectorCommands({ 'method': 'Debugger.resume'})
@@ -165,6 +173,7 @@ function runTests(harness) {
165173
.testHttpResponse('/json/list', checkListResponse)
166174
.testHttpResponse('/json/version', assert.ok)
167175
.runFrontendSession([
176+
testNoUrlsWhenConnected,
168177
testBreakpointOnStart,
169178
testSetBreakpointAndResume,
170179
testInspectScope,

0 commit comments

Comments
 (0)