Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9a954fb

Browse filesBrowse files
legendecasaduh95
authored andcommitted
inspector: add undici http tracking support
Add basic undici http tracking support via inspector protocol. This allows tracking `fetch` calls with an inspector. PR-URL: #56488 Refs: #53946 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 17d59ef commit 9a954fb
Copy full SHA for 9a954fb

File tree

Expand file treeCollapse file tree

6 files changed

+367
-8
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

6 files changed

+367
-8
lines changed
Open diff view settings
Collapse file

‎lib/internal/inspector/network.js‎

Copy file name to clipboardExpand all lines: lib/internal/inspector/network.js
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,28 @@ const {
88
const { now } = require('internal/perf/utils');
99
const kInspectorRequestId = Symbol('kInspectorRequestId');
1010

11+
// https://chromedevtools.github.io/devtools-protocol/1-3/Network/#type-ResourceType
12+
const kResourceType = {
13+
Document: 'Document',
14+
Stylesheet: 'Stylesheet',
15+
Image: 'Image',
16+
Media: 'Media',
17+
Font: 'Font',
18+
Script: 'Script',
19+
TextTrack: 'TextTrack',
20+
XHR: 'XHR',
21+
Fetch: 'Fetch',
22+
Prefetch: 'Prefetch',
23+
EventSource: 'EventSource',
24+
WebSocket: 'WebSocket',
25+
Manifest: 'Manifest',
26+
SignedExchange: 'SignedExchange',
27+
Ping: 'Ping',
28+
CSPViolationReport: 'CSPViolationReport',
29+
Preflight: 'Preflight',
30+
Other: 'Other',
31+
};
32+
1133
/**
1234
* Return a monotonically increasing time in seconds since an arbitrary point in the past.
1335
* @returns {number}
@@ -26,6 +48,7 @@ function getNextRequestId() {
2648

2749
module.exports = {
2850
kInspectorRequestId,
51+
kResourceType,
2952
getMonotonicTime,
3053
getNextRequestId,
3154
};
Collapse file

‎lib/internal/inspector/network_http.js‎

Copy file name to clipboardExpand all lines: lib/internal/inspector/network_http.js
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ const {
1010

1111
const {
1212
kInspectorRequestId,
13+
kResourceType,
1314
getMonotonicTime,
1415
getNextRequestId,
1516
} = require('internal/inspector/network');
1617
const dc = require('diagnostics_channel');
1718
const { Network } = require('inspector');
1819

19-
const kResourceType = 'Other';
2020
const kRequestUrl = Symbol('kRequestUrl');
2121

2222
// Convert a Headers object (Map<string, number | string | string[]>) to a plain object (Map<string, string>)
@@ -79,7 +79,7 @@ function onClientRequestError({ request, error }) {
7979
Network.loadingFailed({
8080
requestId: request[kInspectorRequestId],
8181
timestamp: getMonotonicTime(),
82-
type: kResourceType,
82+
type: kResourceType.Other,
8383
errorText: error.message,
8484
});
8585
}
@@ -96,7 +96,7 @@ function onClientResponseFinish({ request, response }) {
9696
Network.responseReceived({
9797
requestId: request[kInspectorRequestId],
9898
timestamp: getMonotonicTime(),
99-
type: kResourceType,
99+
type: kResourceType.Other,
100100
response: {
101101
url: request[kRequestUrl],
102102
status: response.statusCode,
Collapse file
+141Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
'use strict';
2+
3+
const {
4+
DateNow,
5+
} = primordials;
6+
7+
const {
8+
kInspectorRequestId,
9+
kResourceType,
10+
getMonotonicTime,
11+
getNextRequestId,
12+
} = require('internal/inspector/network');
13+
const dc = require('diagnostics_channel');
14+
const { Network } = require('inspector');
15+
16+
// Convert an undici request headers array to a plain object (Map<string, string>)
17+
function requestHeadersArrayToDictionary(headers) {
18+
const dict = {};
19+
for (let idx = 0; idx < headers.length; idx += 2) {
20+
const key = `${headers[idx]}`;
21+
const value = `${headers[idx + 1]}`;
22+
dict[key] = value;
23+
}
24+
return dict;
25+
};
26+
27+
// Convert an undici response headers array to a plain object (Map<string, string>)
28+
function responseHeadersArrayToDictionary(headers) {
29+
const dict = {};
30+
for (let idx = 0; idx < headers.length; idx += 2) {
31+
const key = `${headers[idx]}`;
32+
const value = `${headers[idx + 1]}`;
33+
const prevValue = dict[key];
34+
35+
if (typeof prevValue === 'string') {
36+
// ChromeDevTools frontend treats 'set-cookie' as a special case
37+
// https://github.com/ChromeDevTools/devtools-frontend/blob/4275917f84266ef40613db3c1784a25f902ea74e/front_end/core/sdk/NetworkRequest.ts#L1368
38+
if (key.toLowerCase() === 'set-cookie') dict[key] = `${prevValue}\n${value}`;
39+
else dict[key] = `${prevValue}, ${value}`;
40+
} else {
41+
dict[key] = value;
42+
}
43+
}
44+
return dict;
45+
};
46+
47+
/**
48+
* When a client request starts, emit Network.requestWillBeSent event.
49+
* https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-requestWillBeSent
50+
* @param {{ request: undici.Request }} event
51+
*/
52+
function onClientRequestStart({ request }) {
53+
const url = `${request.origin}${request.path}`;
54+
request[kInspectorRequestId] = getNextRequestId();
55+
Network.requestWillBeSent({
56+
requestId: request[kInspectorRequestId],
57+
timestamp: getMonotonicTime(),
58+
wallTime: DateNow(),
59+
request: {
60+
url,
61+
method: request.method,
62+
headers: requestHeadersArrayToDictionary(request.headers),
63+
},
64+
});
65+
}
66+
67+
/**
68+
* When a client request errors, emit Network.loadingFailed event.
69+
* https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-loadingFailed
70+
* @param {{ request: undici.Request, error: any }} event
71+
*/
72+
function onClientRequestError({ request, error }) {
73+
if (typeof request[kInspectorRequestId] !== 'string') {
74+
return;
75+
}
76+
Network.loadingFailed({
77+
requestId: request[kInspectorRequestId],
78+
timestamp: getMonotonicTime(),
79+
// TODO(legendecas): distinguish between `undici.request` and `undici.fetch`.
80+
type: kResourceType.Fetch,
81+
errorText: error.message,
82+
});
83+
}
84+
85+
/**
86+
* When response headers are received, emit Network.responseReceived event.
87+
* https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-responseReceived
88+
* @param {{ request: undici.Request, response: undici.Response }} event
89+
*/
90+
function onClientResponseHeaders({ request, response }) {
91+
if (typeof request[kInspectorRequestId] !== 'string') {
92+
return;
93+
}
94+
const url = `${request.origin}${request.path}`;
95+
Network.responseReceived({
96+
requestId: request[kInspectorRequestId],
97+
timestamp: getMonotonicTime(),
98+
// TODO(legendecas): distinguish between `undici.request` and `undici.fetch`.
99+
type: kResourceType.Fetch,
100+
response: {
101+
url,
102+
status: response.statusCode,
103+
statusText: response.statusText,
104+
headers: responseHeadersArrayToDictionary(response.headers),
105+
},
106+
});
107+
}
108+
109+
/**
110+
* When a response is completed, emit Network.loadingFinished event.
111+
* https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-loadingFinished
112+
* @param {{ request: undici.Request, response: undici.Response }} event
113+
*/
114+
function onClientResponseFinish({ request }) {
115+
if (typeof request[kInspectorRequestId] !== 'string') {
116+
return;
117+
}
118+
Network.loadingFinished({
119+
requestId: request[kInspectorRequestId],
120+
timestamp: getMonotonicTime(),
121+
});
122+
}
123+
124+
function enable() {
125+
dc.subscribe('undici:request:create', onClientRequestStart);
126+
dc.subscribe('undici:request:error', onClientRequestError);
127+
dc.subscribe('undici:request:headers', onClientResponseHeaders);
128+
dc.subscribe('undici:request:trailers', onClientResponseFinish);
129+
}
130+
131+
function disable() {
132+
dc.subscribe('undici:request:create', onClientRequestStart);
133+
dc.subscribe('undici:request:error', onClientRequestError);
134+
dc.subscribe('undici:request:headers', onClientResponseHeaders);
135+
dc.subscribe('undici:request:trailers', onClientResponseFinish);
136+
}
137+
138+
module.exports = {
139+
enable,
140+
disable,
141+
};
Collapse file

‎lib/internal/inspector_network_tracking.js‎

Copy file name to clipboardExpand all lines: lib/internal/inspector_network_tracking.js
+2-4Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22

33
function enable() {
44
require('internal/inspector/network_http').enable();
5-
// TODO: add undici request/websocket tracking.
6-
// https://github.com/nodejs/node/issues/53946
5+
require('internal/inspector/network_undici').enable();
76
}
87

98
function disable() {
109
require('internal/inspector/network_http').disable();
11-
// TODO: add undici request/websocket tracking.
12-
// https://github.com/nodejs/node/issues/53946
10+
require('internal/inspector/network_undici').disable();
1311
}
1412

1513
module.exports = {
Collapse file

‎src/node_builtins.cc‎

Copy file name to clipboardExpand all lines: src/node_builtins.cc
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ BuiltinLoader::BuiltinCategories BuiltinLoader::GetBuiltinCategories() const {
120120
#if !HAVE_INSPECTOR
121121
"inspector", "inspector/promises", "internal/util/inspector",
122122
"internal/inspector/network", "internal/inspector/network_http",
123-
"internal/inspector_async_hook", "internal/inspector_network_tracking",
123+
"internal/inspector/network_undici", "internal/inspector_async_hook",
124+
"internal/inspector_network_tracking",
124125
#endif // !HAVE_INSPECTOR
125126

126127
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.