inspector: inspect HTTP response body

PR-URL: https://github.com/nodejs/node/pull/60572
Refs: https://github.com/nodejs/node/issues/53946
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Ryuhei Shima <shimaryuhei@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Kohei Ueno <kohei.ueno119@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
This commit is contained in:
Chengzhong Wu
2025-11-06 22:31:30 +00:00
committed by GitHub
parent e72761fe5e
commit a78f7d9e02
2 changed files with 47 additions and 10 deletions

View File

@@ -17,6 +17,7 @@ const {
sniffMimeType,
} = require('internal/inspector/network');
const { Network } = require('inspector');
const EventEmitter = require('events');
const kRequestUrl = Symbol('kRequestUrl');
@@ -120,6 +121,17 @@ function onClientResponseFinish({ request, response }) {
},
});
// Unlike response.on('data', ...), this does not put the stream into flowing mode.
EventEmitter.prototype.on.call(response, 'data', (chunk) => {
Network.dataReceived({
requestId: request[kInspectorRequestId],
timestamp: getMonotonicTime(),
dataLength: chunk.byteLength,
encodedDataLength: chunk.byteLength,
data: chunk,
});
});
// Wait until the response body is consumed by user code.
response.once('end', () => {
Network.loadingFinished({

View File

@@ -130,6 +130,27 @@ function verifyLoadingFailed({ method, params }) {
assert.strictEqual(typeof params.errorText, 'string');
}
function verifyHttpResponse(response) {
assert.strictEqual(response.statusCode, 200);
const chunks = [];
// Verifies that the inspector does not put the response into flowing mode.
assert.strictEqual(response.readableFlowing, null);
// Verifies that the data listener may be added at a later time, and it can
// still observe the data in full.
queueMicrotask(() => {
response.on('data', (chunk) => {
chunks.push(chunk);
});
assert.strictEqual(response.readableFlowing, true);
});
response.on('end', common.mustCall(() => {
const body = Buffer.concat(chunks).toString();
assert.strictEqual(body, '\nhello world\n');
}));
}
async function testHttpGet() {
const url = `http://127.0.0.1:${httpServer.address().port}/hello-world`;
const requestWillBeSentFuture = once(session, 'Network.requestWillBeSent')
@@ -146,11 +167,7 @@ async function testHttpGet() {
port: httpServer.address().port,
path: '/hello-world',
headers: requestHeaders
}, common.mustCall((res) => {
// Dump the response.
res.on('data', () => {});
res.on('end', () => {});
}));
}, common.mustCall(verifyHttpResponse));
await requestWillBeSentFuture;
const responseReceived = await responseReceivedFuture;
@@ -158,6 +175,12 @@ async function testHttpGet() {
const delta = (loadingFinished.timestamp - responseReceived.timestamp) * 1000;
assert.ok(delta > kDelta);
const responseBody = await session.post('Network.getResponseBody', {
requestId: responseReceived.requestId,
});
assert.strictEqual(responseBody.base64Encoded, false);
assert.strictEqual(responseBody.body, '\nhello world\n');
}
async function testHttpsGet() {
@@ -177,11 +200,7 @@ async function testHttpsGet() {
path: '/hello-world',
rejectUnauthorized: false,
headers: requestHeaders,
}, common.mustCall((res) => {
// Dump the response.
res.on('data', () => {});
res.on('end', () => {});
}));
}, common.mustCall(verifyHttpResponse));
await requestWillBeSentFuture;
const responseReceived = await responseReceivedFuture;
@@ -189,6 +208,12 @@ async function testHttpsGet() {
const delta = (loadingFinished.timestamp - responseReceived.timestamp) * 1000;
assert.ok(delta > kDelta);
const responseBody = await session.post('Network.getResponseBody', {
requestId: responseReceived.requestId,
});
assert.strictEqual(responseBody.base64Encoded, false);
assert.strictEqual(responseBody.body, '\nhello world\n');
}
async function testHttpError() {