Skip to content

Commit 8fa14bc

Browse files
committed
inspector,http: support http body tracking
Signed-off-by: GrinZero <774933704@qq.com>
1 parent 6a3d80f commit 8fa14bc

12 files changed

Lines changed: 819 additions & 37 deletions

doc/api/diagnostics_channel.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,13 +1579,35 @@ Unlike `http.client.request.start`, this event is emitted before the request has
15791579

15801580
Emitted when client starts a request.
15811581

1582+
##### Event: `'http.client.request.bodyChunkSent'`
1583+
1584+
* `request` {http.ClientRequest}
1585+
* `chunk` {Buffer|string|Uint8Array}
1586+
* `encoding` {string|null|undefined}
1587+
1588+
Emitted when a client request body chunk is sent.
1589+
1590+
##### Event: `'http.client.request.bodySent'`
1591+
1592+
* `request` {http.ClientRequest}
1593+
1594+
Emitted when a client request body with at least one chunk has been sent.
1595+
15821596
##### Event: `'http.client.request.error'`
15831597

15841598
* `request` {http.ClientRequest}
15851599
* `error` {Error}
15861600

15871601
Emitted when an error occurs during a client request.
15881602

1603+
##### Event: `'http.client.response.bodyChunkReceived'`
1604+
1605+
* `request` {http.ClientRequest}
1606+
* `response` {http.IncomingMessage}
1607+
* `chunk` {Buffer|Uint8Array}
1608+
1609+
Emitted when raw bytes of a client response body chunk are received.
1610+
15891611
##### Event: `'http.client.response.finish'`
15901612

15911613
* `request` {http.ClientRequest}

lib/_http_client.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ const { URL, urlToHttpOptions, isURL } = require('internal/url');
6363
const {
6464
kOutHeaders,
6565
kNeedDrain,
66+
kOnOutgoingBodyChunkSent,
67+
kOnOutgoingBodySent,
6668
isTraceHTTPEnabled,
6769
traceBegin,
6870
traceEnd,
@@ -102,6 +104,10 @@ const onClientRequestCreatedChannel = dc.channel('http.client.request.created');
102104
const onClientRequestStartChannel = dc.channel('http.client.request.start');
103105
const onClientRequestErrorChannel = dc.channel('http.client.request.error');
104106
const onClientResponseFinishChannel = dc.channel('http.client.response.finish');
107+
const onClientRequestBodyChunkSentChannel =
108+
dc.channel('http.client.request.bodyChunkSent');
109+
const onClientRequestBodySentChannel =
110+
dc.channel('http.client.request.bodySent');
105111

106112
function emitErrorEvent(request, error) {
107113
if (onClientRequestErrorChannel.hasSubscribers) {
@@ -672,6 +678,25 @@ ClientRequest.prototype._implicitHeader = function _implicitHeader() {
672678
this[kOutHeaders]);
673679
};
674680

681+
ClientRequest.prototype[kOnOutgoingBodyChunkSent] =
682+
function onOutgoingBodyChunkSent(chunk, encoding) {
683+
if (onClientRequestBodyChunkSentChannel.hasSubscribers) {
684+
onClientRequestBodyChunkSentChannel.publish({
685+
request: this,
686+
chunk,
687+
encoding,
688+
});
689+
}
690+
};
691+
692+
ClientRequest.prototype[kOnOutgoingBodySent] = function onOutgoingBodySent() {
693+
if (onClientRequestBodySentChannel.hasSubscribers) {
694+
onClientRequestBodySentChannel.publish({
695+
request: this,
696+
});
697+
}
698+
};
699+
675700
ClientRequest.prototype.abort = function abort() {
676701
if (this.aborted) {
677702
return;

lib/_http_common.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const {
2727
Uint8Array,
2828
} = primordials;
2929
const { setImmediate } = require('timers');
30+
const dc = require('diagnostics_channel');
3031

3132
const { methods, allMethods, HTTPParser } = internalBinding('http_parser');
3233
const { getOptionValue } = require('internal/options');
@@ -42,6 +43,7 @@ const {
4243

4344
const kIncomingMessage = Symbol('IncomingMessage');
4445
const kSkipPendingData = Symbol('SkipPendingData');
46+
const kClientRequest = Symbol('kClientRequest');
4547
const kOnMessageBegin = HTTPParser.kOnMessageBegin | 0;
4648
const kOnHeaders = HTTPParser.kOnHeaders | 0;
4749
const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
@@ -50,6 +52,9 @@ const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
5052
const kOnExecute = HTTPParser.kOnExecute | 0;
5153
const kOnTimeout = HTTPParser.kOnTimeout | 0;
5254

55+
const onClientResponseBodyChunkReceivedChannel =
56+
dc.channel('http.client.response.bodyChunkReceived');
57+
5358
const MAX_HEADER_PAIRS = 2000;
5459

5560
// Only called in the slow case where slow means
@@ -120,6 +125,7 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method,
120125
// client only
121126
incoming.statusCode = statusCode;
122127
incoming.statusMessage = statusMessage;
128+
incoming[kClientRequest] = socket?._httpMessage;
123129
}
124130

125131
return parser.onIncoming(incoming, shouldKeepAlive);
@@ -134,6 +140,15 @@ function parserOnBody(b) {
134140

135141
// Pretend this was the result of a stream._read call.
136142
if (!stream._dumped) {
143+
const request = stream[kClientRequest];
144+
if (request !== undefined &&
145+
onClientResponseBodyChunkReceivedChannel.hasSubscribers) {
146+
onClientResponseBodyChunkReceivedChannel.publish({
147+
request,
148+
response: stream,
149+
chunk: b,
150+
});
151+
}
137152
const ret = stream.push(b);
138153
if (!ret)
139154
readStop(this.socket);

lib/_http_outgoing.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@ const { getDefaultHighWaterMark } = require('internal/streams/state');
3838
const assert = require('internal/assert');
3939
const EE = require('events');
4040
const Stream = require('stream');
41-
const { kOutHeaders, utcDate, kNeedDrain } = require('internal/http');
41+
const {
42+
kOnOutgoingBodyChunkSent,
43+
kOnOutgoingBodySent,
44+
kOutHeaders,
45+
utcDate,
46+
kNeedDrain,
47+
} = require('internal/http');
4248
const { Buffer } = require('buffer');
4349
const {
4450
_checkIsHttpToken: checkIsHttpToken,
@@ -87,6 +93,7 @@ const kBytesWritten = Symbol('kBytesWritten');
8793
const kErrored = Symbol('errored');
8894
const kHighWaterMark = Symbol('kHighWaterMark');
8995
const kRejectNonStandardBodyWrites = Symbol('kRejectNonStandardBodyWrites');
96+
const kHasOutgoingBodyChunks = Symbol('kHasOutgoingBodyChunks');
9097

9198
const nop = () => {};
9299

@@ -155,6 +162,7 @@ function OutgoingMessage(options) {
155162
this[kErrored] = null;
156163
this[kHighWaterMark] = options?.highWaterMark ?? getDefaultHighWaterMark();
157164
this[kRejectNonStandardBodyWrites] = options?.rejectNonStandardBodyWrites ?? false;
165+
this[kHasOutgoingBodyChunks] = false;
158166
}
159167
ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype);
160168
ObjectSetPrototypeOf(OutgoingMessage, Stream);
@@ -1002,6 +1010,11 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
10021010
process.nextTick(connectionCorkNT, msg.socket);
10031011
}
10041012

1013+
if (chunk.length !== 0) {
1014+
msg[kHasOutgoingBodyChunks] = true;
1015+
msg[kOnOutgoingBodyChunkSent]?.(chunk, encoding);
1016+
}
1017+
10051018
let ret;
10061019
if (msg.chunkedEncoding && chunk.length !== 0) {
10071020
len ??= typeof chunk === 'string' ? Buffer.byteLength(chunk, encoding) : chunk.byteLength;
@@ -1151,6 +1164,10 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
11511164

11521165
this.finished = true;
11531166

1167+
if (this[kHasOutgoingBodyChunks]) {
1168+
this[kOnOutgoingBodySent]?.();
1169+
}
1170+
11541171
// There is the first message on the outgoing queue, and we've sent
11551172
// everything to the socket.
11561173
debug('outgoing message end.');

lib/internal/http.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ function getGlobalAgent(proxyEnv, Agent) {
270270
}
271271

272272
module.exports = {
273+
kOnOutgoingBodyChunkSent: Symbol('kOnOutgoingBodyChunkSent'),
274+
kOnOutgoingBodySent: Symbol('kOnOutgoingBodySent'),
273275
kOutHeaders: Symbol('kOutHeaders'),
274276
kNeedDrain: Symbol('kNeedDrain'),
275277
kProxyConfig: Symbol('kProxyConfig'),

0 commit comments

Comments
 (0)