Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inspector - Use script name for target title #8243

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 87 additions & 37 deletions src/inspector_agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,14 @@ void PrintDebuggerReadyMessage(int port) {
}

bool AcceptsConnection(inspector_socket_t* socket, const std::string& path) {
return 0 == path.compare(0, sizeof(DEVTOOLS_PATH) - 1, DEVTOOLS_PATH);
return StringEqualNoCaseN(path.c_str(), DEVTOOLS_PATH,
sizeof(DEVTOOLS_PATH) - 1);
}

void Escape(std::string* string) {
for (char& c : *string) {
c = (c == '\"' || c == '\\') ? '_' : c;
}
}

void DisposeInspector(inspector_socket_t* socket, int status) {
Expand Down Expand Up @@ -98,7 +105,21 @@ void SendVersionResponse(inspector_socket_t* socket) {
SendHttpResponse(socket, buffer, len);
}

void SendTargentsListResponse(inspector_socket_t* socket, int port) {
std::string GetProcessTitle() {
// uv_get_process_title will trim the title if it is too long.
char title[2048];
int err = uv_get_process_title(title, sizeof(title));
if (err == 0) {
return title;
} else {
return "Node.js";
}
}

void SendTargentsListResponse(inspector_socket_t* socket,
const std::string& script_name_,
const std::string& script_path_,
int port) {
const char LIST_RESPONSE_TEMPLATE[] =
"[ {"
" \"description\": \"node.js instance\","
Expand All @@ -110,45 +131,60 @@ void SendTargentsListResponse(inspector_socket_t* socket, int port) {
" \"id\": \"%d\","
" \"title\": \"%s\","
" \"type\": \"node\","
" \"url\": \"%s\","
" \"webSocketDebuggerUrl\": \"ws://localhost:%d%s\""
"} ]";
char buffer[sizeof(LIST_RESPONSE_TEMPLATE) + 4096];
char title[2048]; // uv_get_process_title trims the title if too long
int err = uv_get_process_title(title, sizeof(title));
if (err != 0) {
snprintf(title, sizeof(title), "Node.js");
}
char* c = title;
while (*c != '\0') {
if (*c < ' ' || *c == '\"') {
*c = '_';
}
c++;
std::string title = script_name_.empty() ? GetProcessTitle() : script_name_;

// This attribute value is a "best effort" URL that is passed as a JSON
// string. It is not guaranteed to resolve to a valid resource.
std::string url = "file://" + script_path_;

Escape(&title);
Escape(&url);

const int NUMERIC_FIELDS_LENGTH = 5 * 2 + 20; // 2 x port + 1 x pid (64 bit)

int buf_len = sizeof(LIST_RESPONSE_TEMPLATE) + sizeof(DEVTOOLS_HASH) +
sizeof(DEVTOOLS_PATH) * 2 + title.length() +
url.length() + NUMERIC_FIELDS_LENGTH;
std::string buffer(buf_len, '\0');

int len = snprintf(&buffer[0], buf_len, LIST_RESPONSE_TEMPLATE,
DEVTOOLS_HASH, port, DEVTOOLS_PATH, getpid(),
title.c_str(), url.c_str(),
port, DEVTOOLS_PATH);
buffer.resize(len);
ASSERT_LT(len, buf_len); // Buffer should be big enough!
SendHttpResponse(socket, buffer.data(), len);
}

const char* match_path_segment(const char* path, const char* expected) {
size_t len = strlen(expected);
if (StringEqualNoCaseN(path, expected, len)) {
if (path[len] == '/') return path + len + 1;
if (path[len] == '\0') return path + len;
}
size_t len = snprintf(buffer, sizeof(buffer), LIST_RESPONSE_TEMPLATE,
DEVTOOLS_HASH, port, DEVTOOLS_PATH, getpid(),
title, port, DEVTOOLS_PATH);
ASSERT_LT(len, sizeof(buffer));
SendHttpResponse(socket, buffer, len);
return nullptr;
}

bool RespondToGet(inspector_socket_t* socket, const std::string& path,
bool RespondToGet(inspector_socket_t* socket, const std::string& script_name_,
const std::string& script_path_, const std::string& path,
int port) {
const char PATH[] = "/json";
const char PATH_LIST[] = "/json/list";
const char PATH_VERSION[] = "/json/version";
const char PATH_ACTIVATE[] = "/json/activate/";
if (0 == path.compare(0, sizeof(PATH_VERSION) - 1, PATH_VERSION)) {
const char* command = match_path_segment(path.c_str(), "/json");
if (command == nullptr)
return false;

if (match_path_segment(command, "list") || command[0] == '\0') {
SendTargentsListResponse(socket, script_name_, script_path_, port);
} else if (match_path_segment(command, "version")) {
SendVersionResponse(socket);
} else if (0 == path.compare(0, sizeof(PATH_LIST) - 1, PATH_LIST) ||
0 == path.compare(0, sizeof(PATH) - 1, PATH)) {
SendTargentsListResponse(socket, port);
} else if (0 == path.compare(0, sizeof(PATH_ACTIVATE) - 1, PATH_ACTIVATE) &&
atoi(path.substr(sizeof(PATH_ACTIVATE) - 1).c_str()) == getpid()) {
} else {
const char* pid = match_path_segment(command, "activate");
if (pid == nullptr || atoi(pid) != getpid())
return false;
const char TARGET_ACTIVATED[] = "Target activated";
SendHttpResponse(socket, TARGET_ACTIVATED, sizeof(TARGET_ACTIVATED) - 1);
} else {
return false;
}
return true;
}
Expand All @@ -166,7 +202,7 @@ class AgentImpl {
~AgentImpl();

// Start the inspector agent thread
bool Start(v8::Platform* platform, int port, bool wait);
bool Start(v8::Platform* platform, const char* path, int port, bool wait);
// Stop the inspector agent
void Stop();

Expand Down Expand Up @@ -227,6 +263,9 @@ class AgentImpl {
int frontend_session_id_;
int backend_session_id_;

std::string script_name_;
std::string script_path_;

friend class ChannelImpl;
friend class DispatchOnInspectorBackendTask;
friend class SetConnectedTask;
Expand Down Expand Up @@ -442,10 +481,13 @@ void InspectorWrapConsoleCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
array).ToLocalChecked());
}

bool AgentImpl::Start(v8::Platform* platform, int port, bool wait) {
bool AgentImpl::Start(v8::Platform* platform, const char* path,
int port, bool wait) {
auto env = parent_env_;
inspector_ = new V8NodeInspector(this, env, platform);
platform_ = platform;
if (path != nullptr)
script_name_ = path;

InstallInspectorOnProcess();

Expand Down Expand Up @@ -566,7 +608,8 @@ bool AgentImpl::OnInspectorHandshakeIO(inspector_socket_t* socket,
AgentImpl* agent = static_cast<AgentImpl*>(socket->data);
switch (state) {
case kInspectorHandshakeHttpGet:
return RespondToGet(socket, path, agent->port_);
return RespondToGet(socket, agent->script_name_, agent->script_path_, path,
agent->port_);
case kInspectorHandshakeUpgrading:
return AcceptsConnection(socket, path);
case kInspectorHandshakeUpgraded:
Expand Down Expand Up @@ -635,6 +678,12 @@ void AgentImpl::WorkerRunIO() {
err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO);
CHECK_EQ(err, 0);
io_thread_req_.data = this;
if (!script_name_.empty()) {
uv_fs_t req;
if (0 == uv_fs_realpath(&child_loop_, &req, script_name_.c_str(), nullptr))
script_path_ = std::string(reinterpret_cast<char*>(req.ptr));
uv_fs_req_cleanup(&req);
}
uv_tcp_init(&child_loop_, &server);
uv_ip4_addr("0.0.0.0", port_, &addr);
server.data = this;
Expand Down Expand Up @@ -752,8 +801,9 @@ Agent::~Agent() {
delete impl;
}

bool Agent::Start(v8::Platform* platform, int port, bool wait) {
return impl->Start(platform, port, wait);
bool Agent::Start(v8::Platform* platform, const char* path,
int port, bool wait) {
return impl->Start(platform, path, port, wait);
}

void Agent::Stop() {
Expand Down
2 changes: 1 addition & 1 deletion src/inspector_agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Agent {
~Agent();

// Start the inspector agent thread
bool Start(v8::Platform* platform, int port, bool wait);
bool Start(v8::Platform* platform, const char* path, int port, bool wait);
// Stop the inspector agent
void Stop();

Expand Down
20 changes: 13 additions & 7 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,10 @@ static struct {
platform_ = nullptr;
}

bool StartInspector(Environment *env, int port, bool wait) {
bool StartInspector(Environment *env, const char* script_path,
int port, bool wait) {
#if HAVE_INSPECTOR
return env->inspector_agent()->Start(platform_, port, wait);
return env->inspector_agent()->Start(platform_, script_path, port, wait);
#else
return true;
#endif // HAVE_INSPECTOR
Expand All @@ -220,7 +221,8 @@ static struct {
void Initialize(int thread_pool_size) {}
void PumpMessageLoop(Isolate* isolate) {}
void Dispose() {}
bool StartInspector(Environment *env, int port, bool wait) {
bool StartInspector(Environment *env, const char* script_path,
int port, bool wait) {
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
return false; // make compiler happy
}
Expand Down Expand Up @@ -3766,10 +3768,11 @@ static void DispatchMessagesDebugAgentCallback(Environment* env) {
}


static void StartDebug(Environment* env, bool wait) {
static void StartDebug(Environment* env, const char* path, bool wait) {
CHECK(!debugger_running);
if (use_inspector) {
debugger_running = v8_platform.StartInspector(env, inspector_port, wait);
debugger_running = v8_platform.StartInspector(env, path, inspector_port,
wait);
} else {
env->debugger_agent()->set_dispatch_handler(
DispatchMessagesDebugAgentCallback);
Expand Down Expand Up @@ -3831,7 +3834,7 @@ static void DispatchDebugMessagesAsyncCallback(uv_async_t* handle) {
Environment* env = Environment::GetCurrent(isolate);
Context::Scope context_scope(env->context());

StartDebug(env, false);
StartDebug(env, nullptr, false);
EnableDebug(env);
}

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

// Start debug agent when argv has --debug
if (instance_data->use_debug_agent()) {
StartDebug(&env, debug_wait_connect);
const char* path = instance_data->argc() > 1
? instance_data->argv()[1]
: nullptr;
StartDebug(&env, path, debug_wait_connect);
if (use_inspector && !debugger_running) {
exit(12);
}
Expand Down