Skip to content

Commit 782620f

Browse files
committed
src: add /json/protocol endpoint to inspector
Embed the compressed and minified protocol.json from the bundled v8_inspector and make it available through the /json/protocol endpoint. Refs: nodejs/diagnostics#52 PR-URL: #7491 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent a8d2c9d commit 782620f

File tree

7 files changed

+113
-1
lines changed

7 files changed

+113
-1
lines changed

deps/zlib/zlib.gyp

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
{
1313
'target_name': 'zlib',
1414
'type': 'static_library',
15+
'defines': [ 'ZLIB_CONST' ],
1516
'sources': [
1617
'adler32.c',
1718
'compress.c',
@@ -44,6 +45,7 @@
4445
'.',
4546
],
4647
'direct_dependent_settings': {
48+
'defines': [ 'ZLIB_CONST' ],
4749
'include_dirs': [
4850
'.',
4951
],
@@ -72,10 +74,12 @@
7274
'direct_dependent_settings': {
7375
'defines': [
7476
'USE_SYSTEM_ZLIB',
77+
'ZLIB_CONST',
7578
],
7679
},
7780
'defines': [
7881
'USE_SYSTEM_ZLIB',
82+
'ZLIB_CONST',
7983
],
8084
'link_settings': {
8185
'libraries': [

node.gyp

+29
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@
323323
'dependencies': [
324324
'deps/v8_inspector/third_party/v8_inspector/platform/'
325325
'v8_inspector/v8_inspector.gyp:v8_inspector_stl',
326+
'v8_inspector_compress_protocol_json#host',
326327
],
327328
'include_dirs': [
328329
'deps/v8_inspector/third_party/v8_inspector',
@@ -651,6 +652,34 @@
651652
} ]
652653
]
653654
},
655+
{
656+
'target_name': 'v8_inspector_compress_protocol_json',
657+
'type': 'none',
658+
'toolsets': ['host'],
659+
'conditions': [
660+
[ 'v8_inspector=="true"', {
661+
'actions': [
662+
{
663+
'action_name': 'v8_inspector_compress_protocol_json',
664+
'process_outputs_as_sources': 1,
665+
'inputs': [
666+
'deps/v8_inspector/third_party/'
667+
'v8_inspector/platform/v8_inspector/js_protocol.json',
668+
],
669+
'outputs': [
670+
'<(SHARED_INTERMEDIATE_DIR)/v8_inspector_protocol_json.h',
671+
],
672+
'action': [
673+
'python',
674+
'tools/compress_json.py',
675+
'<@(_inputs)',
676+
'<@(_outputs)',
677+
],
678+
},
679+
],
680+
}],
681+
],
682+
},
654683
{
655684
'target_name': 'node_js2c',
656685
'type': 'none',

src/inspector_agent.cc

+28
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "node_version.h"
99
#include "v8-platform.h"
1010
#include "util.h"
11+
#include "zlib.h"
1112

1213
#include "platform/v8_inspector/public/InspectorVersion.h"
1314
#include "platform/v8_inspector/public/V8Inspector.h"
@@ -41,6 +42,10 @@ const char TAG_DISCONNECT[] = "#disconnect";
4142
const char DEVTOOLS_PATH[] = "/node";
4243
const char DEVTOOLS_HASH[] = V8_INSPECTOR_REVISION;
4344

45+
static const uint8_t PROTOCOL_JSON[] = {
46+
#include "v8_inspector_protocol_json.h" // NOLINT(build/include_order)
47+
};
48+
4449
void PrintDebuggerReadyMessage(int port) {
4550
fprintf(stderr, "Debugger listening on port %d.\n"
4651
"Warning: This is an experimental feature and could change at any time.\n"
@@ -161,6 +166,27 @@ void SendTargentsListResponse(InspectorSocket* socket,
161166
SendHttpResponse(socket, buffer.data(), len);
162167
}
163168

169+
void SendProtocolJson(InspectorSocket* socket) {
170+
z_stream strm;
171+
strm.zalloc = Z_NULL;
172+
strm.zfree = Z_NULL;
173+
strm.opaque = Z_NULL;
174+
CHECK_EQ(Z_OK, inflateInit(&strm));
175+
static const size_t kDecompressedSize =
176+
PROTOCOL_JSON[0] * 0x10000u +
177+
PROTOCOL_JSON[1] * 0x100u +
178+
PROTOCOL_JSON[2];
179+
strm.next_in = PROTOCOL_JSON + 3;
180+
strm.avail_in = sizeof(PROTOCOL_JSON) - 3;
181+
std::vector<char> data(kDecompressedSize);
182+
strm.next_out = reinterpret_cast<Byte*>(&data[0]);
183+
strm.avail_out = data.size();
184+
CHECK_EQ(Z_STREAM_END, inflate(&strm, Z_FINISH));
185+
CHECK_EQ(0, strm.avail_out);
186+
CHECK_EQ(Z_OK, inflateEnd(&strm));
187+
SendHttpResponse(socket, &data[0], data.size());
188+
}
189+
164190
const char* match_path_segment(const char* path, const char* expected) {
165191
size_t len = strlen(expected);
166192
if (StringEqualNoCaseN(path, expected, len)) {
@@ -179,6 +205,8 @@ bool RespondToGet(InspectorSocket* socket, const std::string& script_name_,
179205

180206
if (match_path_segment(command, "list") || command[0] == '\0') {
181207
SendTargentsListResponse(socket, script_name_, script_path_, port);
208+
} else if (match_path_segment(command, "protocol")) {
209+
SendProtocolJson(socket);
182210
} else if (match_path_segment(command, "version")) {
183211
SendVersionResponse(socket);
184212
} else {

test/common.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ exports.testDir = __dirname;
1616
exports.fixturesDir = path.join(exports.testDir, 'fixtures');
1717
exports.libDir = path.join(exports.testDir, '../lib');
1818
exports.tmpDirName = 'tmp';
19+
// PORT should match the definition in test/testpy/__init__.py.
1920
exports.PORT = +process.env.NODE_COMMON_PORT || 12346;
2021
exports.isWindows = process.platform === 'win32';
2122
exports.isWOW64 = exports.isWindows &&
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Flags: --inspect={PORT}
2+
'use strict';
3+
4+
const common = require('../common');
5+
const assert = require('assert');
6+
const http = require('http');
7+
8+
const options = {
9+
path: '/json/protocol',
10+
port: common.PORT,
11+
host: common.localhostIPv4,
12+
};
13+
14+
http.get(options, common.mustCall((res) => {
15+
let body = '';
16+
res.setEncoding('utf8');
17+
res.on('data', (data) => body += data);
18+
res.on('end', common.mustCall(() => {
19+
assert(body.length > 0);
20+
assert.deepStrictEqual(JSON.stringify(JSON.parse(body)), body);
21+
}));
22+
}));

test/testpy/__init__.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ def GetCommand(self):
6161
source = open(self.file).read()
6262
flags_match = FLAGS_PATTERN.search(source)
6363
if flags_match:
64-
result += flags_match.group(1).strip().split()
64+
# PORT should match the definition in test/common.js.
65+
env = { 'PORT': int(os.getenv('NODE_COMMON_PORT', '12346')) }
66+
env['PORT'] += self.thread_id * 100
67+
result += flags_match.group(1).strip().format(**env).split()
6568
files_match = FILES_PATTERN.search(source);
6669
additional_files = []
6770
if files_match:

tools/compress_json.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python
2+
3+
import json
4+
import struct
5+
import sys
6+
import zlib
7+
8+
if __name__ == '__main__':
9+
fp = open(sys.argv[1])
10+
obj = json.load(fp)
11+
text = json.dumps(obj, separators=(',', ':'))
12+
data = zlib.compress(text, zlib.Z_BEST_COMPRESSION)
13+
14+
# To make decompression a little easier, we prepend the compressed data
15+
# with the size of the uncompressed data as a 24 bits BE unsigned integer.
16+
assert len(text) < 1 << 24, 'Uncompressed JSON must be < 16 MB.'
17+
data = struct.pack('>I', len(text))[1:4] + data
18+
19+
step = 20
20+
slices = (data[i:i+step] for i in xrange(0, len(data), step))
21+
slices = map(lambda s: ','.join(str(ord(c)) for c in s), slices)
22+
text = ',\n'.join(slices)
23+
24+
fp = open(sys.argv[2], 'w')
25+
fp.write(text)

0 commit comments

Comments
 (0)